I am using Jhipster Spring boot + angular 6. But i'm having trouble because of the hash(#) in URL. It is affecting SEO.
I tried setting useHash: false in app-routing-module.ts.
But then the API is not working when I run the project via npm start.
I think somewhere in Java files I have to change a configuration to remove # from the URL.
Here is my WebConfigurer code,
#Configuration
public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer<WebServerFactory> {
private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);
private final Environment env;
private final JHipsterProperties jHipsterProperties;
private MetricRegistry metricRegistry;
public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) {
this.env = env;
this.jHipsterProperties = jHipsterProperties;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
if (env.getActiveProfiles().length != 0) {
log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles());
}
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
initMetrics(servletContext, disps);
log.info("Web application fully configured");
}
/**
* Customize the Servlet engine: Mime types, the document root, the cache.
*/
#Override
public void customize(WebServerFactory server) {
setMimeMappings(server);
/*
* Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288
* HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1.
* See the JHipsterProperties class and your application-*.yml configuration files
* for more information.
*/
if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) &&
server instanceof UndertowServletWebServerFactory) {
((UndertowServletWebServerFactory) server)
.addBuilderCustomizers(builder ->
builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
}
}
private void setMimeMappings(WebServerFactory server) {
if (server instanceof ConfigurableServletWebServerFactory) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
// IE issue, see https://github.com/jhipster/generator-jhipster/pull/711
mappings.add("html", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase());
// CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64
mappings.add("json", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase());
ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server;
servletWebServer.setMimeMappings(mappings);
}
}
/**
* Initializes Metrics.
*/
private void initMetrics(ServletContext servletContext, EnumSet<DispatcherType> disps) {
log.debug("Initializing Metrics registries");
servletContext.setAttribute(InstrumentedFilter.REGISTRY_ATTRIBUTE,
metricRegistry);
servletContext.setAttribute(MetricsServlet.METRICS_REGISTRY,
metricRegistry);
log.debug("Registering Metrics Filter");
FilterRegistration.Dynamic metricsFilter = servletContext.addFilter("webappMetricsFilter",
new InstrumentedFilter());
metricsFilter.addMappingForUrlPatterns(disps, true, "/*");
metricsFilter.setAsyncSupported(true);
log.debug("Registering Metrics Servlet");
ServletRegistration.Dynamic metricsAdminServlet =
servletContext.addServlet("metricsServlet", new MetricsServlet());
metricsAdminServlet.addMapping("/management/metrics/*");
metricsAdminServlet.setAsyncSupported(true);
metricsAdminServlet.setLoadOnStartup(2);
}
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = jHipsterProperties.getCors();
if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) {
log.debug("Registering CORS filter");
source.registerCorsConfiguration("/api/**", config);
source.registerCorsConfiguration("/management/**", config);
source.registerCorsConfiguration("/v2/api-docs", config);
}
return new CorsFilter(source);
}
#Autowired(required = false)
public void setMetricRegistry(MetricRegistry metricRegistry) {
this.metricRegistry = metricRegistry;
}
}
Here is my AngularRouteFilter servlet code,
public class AngularRouteFilter extends OncePerRequestFilter {
// add the values you want to redirect for
private static final Pattern PATTERN = Pattern.compile("^/((api|swagger-ui|management|swagger-resources)/|favicon\\.ico|v2/api-docs).*");
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
if (isServerRoute(request)) {
filterChain.doFilter(request, response);
} else {
RequestDispatcher rd = request.getRequestDispatcher("/");
rd.forward(request, response);
}
}
protected static boolean isServerRoute(HttpServletRequest request) {
if (request.getMethod().equals("GET")) {
String uri = request.getRequestURI();
if (uri.startsWith("/app")){
return true;
}
return PATTERN.matcher(uri).matches();
}
return true;
}
}
here is my Swagger index.html(swagger-ui/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
<link href='./dist/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='./dist/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='./dist/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='./dist/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
<link href='./dist/css/print.css' media='print' rel='stylesheet' type='text/css'/>
<script src='./dist/lib/object-assign-pollyfill.js' type='text/javascript'></script>
<script src='./dist/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='./dist/lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='./dist/lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='./dist/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='./dist/lib/handlebars-4.0.5.js' type='text/javascript'></script>
<script src='./dist/lib/lodash.min.js' type='text/javascript'></script>
<script src='./dist/lib/backbone-min.js' type='text/javascript'></script>
<script src='./dist/swagger-ui.min.js' type='text/javascript'></script>
<script src='./dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
<script src='./dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
<script src='./dist/lib/jsoneditor.min.js' type='text/javascript'></script>
<script src='./dist/lib/marked.js' type='text/javascript'></script>
<script src='./dist/lib/swagger-oauth.js' type='text/javascript'></script>
<!-- Some basic translations -->
<!-- <script src='lang/translator.js' type='text/javascript'></script> -->
<!-- <script src='lang/ru.js' type='text/javascript'></script> -->
<!-- <script src='lang/en.js' type='text/javascript'></script> -->
<script type="text/javascript">
$(function() {
var springfox = {
"baseUrl": function() {
var urlMatches = /(.*)\/swagger-ui\/index.html.*/.exec(window.location.href);
return urlMatches[1];
},
"securityConfig": function(cb) {
$.getJSON(this.baseUrl() + "/swagger-resources/configuration/security", function(data) {
cb(data);
});
},
"uiConfig": function(cb) {
alert(cb);
$.getJSON(this.baseUrl() + "/swagger-resources/configuration/ui", function(data) {
cb(data);
});
}
};
window.springfox = springfox;
window.oAuthRedirectUrl = springfox.baseUrl() + './dist/o2c.html'
window.springfox.uiConfig(function(data) {
window.swaggerUi = new SwaggerUi({
dom_id: "swagger-ui-container",
validatorUrl: data.validatorUrl,
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
onComplete: function(swaggerApi, swaggerUi) {
initializeSpringfox();
if (window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
$('pre code').each(function(i, e) {
hljs.highlightBlock(e)
});
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "none",
apisSorter: "alpha",
showRequestHeaders: false
});
initializeBaseUrl();
$('#select_baseUrl').change(function() {
window.swaggerUi.headerView.trigger('update-swagger-ui', {
url: $('#select_baseUrl').val()
});
addApiKeyAuthorization();
});
function addApiKeyAuthorization() {
var authToken = JSON.parse(localStorage.getItem("jhi-authenticationtoken") || sessionStorage.getItem("jhi-authenticationtoken"));
var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", "Bearer " + authToken, "header");
window.swaggerUi.api.clientAuthorizations.add("bearer", apiKeyAuth);
}
function getCSRF() {
var name = "XSRF-TOKEN=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1);
if (c.indexOf(name) !== -1) return c.substring(name.length,c.length);
}
return "";
}
function log() {
if ('console' in window) {
console.log.apply(console, arguments);
}
}
function oAuthIsDefined(security) {
return security.clientId
&& security.clientSecret
&& security.appName
&& security.realm;
}
function initializeSpringfox() {
var security = {};
window.springfox.securityConfig(function(data) {
security = data;
if (typeof initOAuth === "function" && oAuthIsDefined(security)) {
initOAuth(security);
}
});
}
});
function maybePrefix(location, withRelativePath) {
var pat = /^https?:\/\//i;
if (pat.test(location)) {
return location;
}
return withRelativePath + location;
}
function initializeBaseUrl() {
var relativeLocation = springfox.baseUrl();
$('#input_baseUrl').hide();
$.getJSON(relativeLocation + "/swagger-resources", function(data) {
var $urlDropdown = $('#select_baseUrl');
$urlDropdown.empty();
$.each(data, function(i, resource) {
var option = $('<option></option>')
.attr("value", maybePrefix(resource.location, relativeLocation))
.text(resource.name + " (" + resource.location + ")");
$urlDropdown.append(option);
});
$urlDropdown.change();
});
}
});
</script>
</head>
<body class="swagger-section">
<div id='header'>
<div class="swagger-ui-wrap">
<a id="logo" href="http://swagger.io">swagger</a>
<form id='api_selector'>
<div class='input'>
<select id="select_baseUrl" name="select_baseUrl"></select>
</div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/>
</div>
</form>
</div>
</div>
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate> </div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body>
</html>
here is docs.component.html
<iframe src="swagger-ui/index.html" width="100%" height="900" seamless
target="_top" title="Swagger UI" class="border-0"></iframe>
here my server code is running perfectly # localhost:6060. Butm localhost:6060/api/docs opening a blank page.
here is the screen shot,
Please suggest me where i am doing wrong.
Solution using a servlet filter
First step is to configure client, set useHash: false in app-routing-module.ts
In index.html, change <base href="./" /> to <base href="/" />
But it's not enough because it does not support deep linking which means linking to a client route from an external link like from a mail message or from another web site, or veen when refreshing page in browser.
When deep linking, the server receives the request first and if the URL has to be handled by client side, it will not be found so our server app must detect whether the URL has to be served as-is by server (e.g. all API calls) or forwarded to index.html so that the javascript app can interpret it.
One solution is to use pattern matching in a servlet filter (Html5RouteFilter) that we register in WebConfigurer.java
WebConfigurer.java
#Bean
public Html5RouteFilter html5RouteFilter() {
return new Html5RouteFilter();
}
Html5RouteFilter.java
package com.mycompany.myapp.web;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;
/**
* Filter that distinguishes between client routes and server routes when you don't use '#' in client routes.
*/
public class Html5RouteFilter extends OncePerRequestFilter {
private Logger log = LoggerFactory.getLogger(getClass());
// These are the URIs that should be processed server-side
private static final Pattern PATTERN = Pattern.compile("^/((api|content|i18n|management|swagger-ui|swagger-resources)/|error|h2-console|swagger-resources|favicon\\.ico|v2/api-docs).*");
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
if (isServerRoute(request)) {
filterChain.doFilter(request, response);
} else {
RequestDispatcher rd = request.getRequestDispatcher("/");
rd.forward(request, response);
}
}
protected static boolean isServerRoute(HttpServletRequest request) {
if (request.getMethod().equals("GET")) {
String uri = request.getRequestURI();
if (uri.startsWith("/app")) {
return true;
}
return PATTERN.matcher(uri).matches();
}
return true;
}
}
Solution using a REST controller
First step is to configure client, set useHash: false in app-routing-module.ts
In index.html, change <base href="./" /> to <base href="/" />
But it's not enough because it does not support deep linking which means linking to a client route from an external link like from a mail message or from another web site, or veen when refreshing page in browser.
When deep linking, the server receives the request first and if the URL has to be handled by client side, it will not be found so our server app must detect whether the URL has to be served as-is by server (e.g. all API calls) or forwarded to index.html so that the javascript app can interpret it.
ClientRouteForwarder .java
package com.mycompany.myapp.web.rest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* A REST controller that forwards all GET requests that did not match a RequestMapping to /index.html so that
* client routes can be handled by client code in browser.
*
* This works because Spring resolves exact matches first.
*/
#Controller
public class ClientRouteForwarder {
#GetMapping(value = "/**/{[path:[^\\.]*}")
public String forward() {
return "forward:/";
}
}
As per their official documentation Configuring html5, AngularJS uses a “#” in it’s urls. HTML5Mode of AngularJS removes these “#” from URL.
Activate HTML 5 Mode
Create html5.mode.config.js file in webapp/app/blocks/config/ directory:
(function() {
'use strict';
angular
.module('<YourAppName>')
.config(html5ModeConfig);
html5ModeConfig.$inject = ['$locationProvider'];
function html5ModeConfig($locationProvider) {
$locationProvider.html5Mode({ enabled: true, requireBase: true });
}
})();
Then open index.html and add this line in head tag:
<base href="/">
Related
My problem comes when I try to implement SockJS on Java Vertx with a simple broadcast message example , I only get the "Welcome to SockJS message!" on the server side, but the frontend and the backend do not seem to be connecting. I am new to Vertx and SockJS, so any help will be very much appreciated.
Here is my index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Push Notifications</title>
<script src="client.js"> </script>
<script src="https://unpkg.io/sockjs-client#1.5.0/dist/sockjs.min.js"></script>
</head>
<body>
<h1>Push Notifications With Vertx</h1>
<script>
var sock;
function openSock() {
sock = new SockJS('http://localhost:8080/myapp');
sock.onopen = function() {
sock.onopen = function() {
console.log('open');
};
sock.onmessage = function(e) {
console.log('message', e.data);
};
sock.onevent = function(event, message) {
console.log('event: %o, message:%o', event, message);
return true; // in order to signal that the message has been processed
};
sock.onerror = function(e) {
console.error(e);
}
sock.onunhandled = function(json) {
console.log('this message has no address:', json);
};
sock.onclose = function() {
console.log('close');
};
sock.send('test');
}
}
openSock();
</script>
</body>
</html>
and here is my MainVerticle.java
package com.bcm.vertxmvn;
import io.vertx.core.AbstractVerticle;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MainVerticle extends AbstractVerticle {
private static final Logger LOGGER = LoggerFactory.getLogger(MainVerticle.class);
#Override
public void start() {
Router router = Router.router(vertx);
SockJSHandlerOptions options = new SockJSHandlerOptions()
.setHeartbeatInterval(2000);
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options);
router.mountSubRouter("/myapp", sockJSHandler.socketHandler(sockJSSocket -> {
// Just echo the data back
sockJSSocket.handler(sockJSSocket::write);
}));
vertx.createHttpServer().requestHandler(router).listen(8080);
}
}
I have made an AJAX call to a JSP, which in turn calls a Java method in a separate Java class. All files are in the same folder.
For some reason, I can't get the correct value returned to AJAX. It simply prints the whole JSP content.
JavaScript:
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if(true){
alert('hello!');
var response = xhr.responseText;
alert(response);
document.getElementById('newgame').innerHTML = xhr.responseText;
}
};
xhr.open('GET', 'javaconnect.jsp', true);
xhr.send(null);
JSP:
<%# page import="com.example.Server"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<%
Server tc = new Server();
out.print(tc.highScore());
%>
</body>
</html>
Java class:
package com.example;
public class Server {
public String highScore() {
return "hello!!!";
}
}
The best solution is to use a Servlet to make the control layer in place of jsp that instantiates the Server class, like:
public class HelloWorld extends HttpServlet {
protected void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Server tc = new Server();
String txt = tc.highScore();
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(txt);
}
}
Do not forget to map the servlet and change the url of the ajax call.
You can test call
I have a web interface through which I can perform/apply actions on backend systems like Hadoop. I am trying to code a functionality which allows me to track the status of the server. Basically to see if the server/service is up or down. I need to do this every 2 minutes. So should I go with a Websocket or a SSE(Server Sent Event) for this..I have written this code to perform this. However the moment I code for checking the status every 2 minutes. It becomes a blocking call and I am unable to perform any other functionality of the Web UI
Following is the Code
import java.io.*;
import java.net.*;
import java.util.concurrent.TimeUnit;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/echo")
public class Websocket {
#OnOpen
public void onOpen(Session session){
System.out.println(session.getId() + " has opened a connection");
try {
session.getBasicRemote().sendText("Connection Established");
} catch (IOException ex) {
ex.printStackTrace();
}
onping(session);
}
public void onping(Session session) throws IOException
{ if (session.isOpen())
{
session.getBasicRemote().sendText("In PING");
String ip = "200.168.100.46";
InetAddress inet = InetAddress.getByName(ip);
if(inet.isReachable(1000))
{
session.getBasicRemote().sendText("Alive");
}
}
else
{
System.out.println("Error");
}
}
#OnClose
public void onClose(Session session){
System.out.println("Session " +session.getId()+" has ended");
}
}
And the Client Side Code is
<!DOCTYPE html>
<html>
<head>
<title>Websocket</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div>
<input type="text" id="messageinput"/>
</div>
<div>
<button type="button" onclick="openSocket();" >Open</button>
<button type="button" onclick="closeSocket();" >Close</button>
<button type="button" onclick="pingSocket();" >Ping</button>
</div>
<!-- Server responses get written here -->
<div id="messages"></div>
<!-- Script to utilise the WebSocket -->
<script type="text/javascript">
var webSocket;
var messages = document.getElementById("messages");
function openSocket(){
// Ensures only one connection is open at a time
if(webSocket !== undefined && webSocket.readyState !== WebSocket.CLOSED){
writeResponse("WebSocket is already opened.");
return;
}
// Create a new instance of the websocket
webSocket = new WebSocket("ws://localhost:8080/Websocket/echo");
/**
* Binds functions to the listeners for the websocket.
*/
webSocket.onopen = function(event){
// For reasons I can't determine, onopen gets called twice
// and the first time event.data is undefined.
// Leave a comment if you know the answer.
if(event.data === undefined)
return;
writeResponse(event.data);
};
webSocket.onmessage = function(event){
writeResponse(event.data);
};
webSocket.onclose = function(event){
writeResponse("Connection closed");
};
}
/**
* Sends the value of the text input to the server
*/
function send(){
var text = document.getElementById("messageinput").value;
webSocket.send(text);
}
function pingSocket(){
var text = document.getElementById("messageinput").value;
webSocket.send("PING");
}
function closeSocket(){
var text = document.getElementById("messageinput").value;
webSocket.send(text);
webSocket.close();
}
function writeResponse(text){
messages.innerHTML += "<br/>" + text;
}
</script>
</body>
</html>
So can you let me know what am i doing wrong?
Thanks
I am using log4j to log my data. I wan to be able to view the log files realtime alongside my web-app in a browser. There are standalone tools like Chainsaw which are quite good, but they don't serve the purpos eof viewing logs real-time in a browser.
Can anybody help me with this?
A simple example would be:
Servlet (change path of log file as needed):
#WebServlet(name = "Log", urlPatterns = { "/log" })
public class LogServlet extends HttpServlet {
private static final long serialVersionUID = 7503953988166684851L;
public LogServlet() {
super();
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Path path = FileSystems.getDefault()
.getPath("/path/to/tomcat/logs", "catalina.out");
StringBuilder logContent = new StringBuilder();
logContent.append("<pre>");
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);) {
String line = null;
while ((line = reader.readLine()) != null) {
logContent.append(line).append("<br/>");
}
} catch (IOException x) {
// Take care of that
}
logContent.append("</pre>");
resp.getWriter().print(logContent.toString());
}
#Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}
}
HTML page:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Log viewer</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>window.jQuery || document.write(unescape('%3Cscript src="http://jquery.com/jquery-wp-content/themes/jquery/js/jquery-1.10.2.min.js"%3E%3C/script%3E'))
</script>
<script type="text/javascript">
var logging = false;
function refreshLog() {
if (logging) {
$.get('/log', function(data) {
$('#log').html(data);
});
}
if (logging) {
setTimeout(function() {
refreshLog()
}, 5000);
}
}
function toggleLogs() {
if (logging) {
logging = false;
$("#tog").val("Start");
} else {
logging = true;
$("#tog").val("Stop");
refreshLog();
}
}
</script>
</head>
<body style="width: 100%; padding: 0; margin: 0">
<input type="button" id="tog" onclick="toggleLogs()" value="Start" />
<div id="log" style="width: 100%; padding: 0; margin: 0"></div>
</body>
</html>
You can use psi-probe. It has a built-in functionality to access logs in real-time, change log level, download, etc...
I'm getting a null JsonNode object in the following code. There's something wrong with the client javascript. If I run a curl command with a POST request, I get the correct response. If I run the same in the below mentioned Javascript - I get a null for the JsonNode object. Here's the code
Application.java
package controllers;
import org.codehaus.jackson.JsonNode;
import play.Routes;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;
public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
public static Result receiveData() {
response().setContentType("application/json");
JsonNode json = request().body().asJson();
if(json == null) {
return badRequest("Expecting Json data");
} else {
String name = json.findPath("name").getTextValue();
if(name == null) {
return badRequest("Missing parameter [name]");
} else {
return ok("Hello " + name);
}
}
}
public static Result javascriptRoutes() {
response().setContentType("text/javascript");
return ok(
Routes.javascriptRouter("jsRoutes",
// Routes
controllers.routes.javascript.Application.receiveData()
)
);
}
}
Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / controllers.Application.index()
POST /receiveData controllers.Application.receiveData()
GET /assets/javascripts/routes controllers.Application.javascriptRoutes()
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
main.scala.html
#(title: String)(content: Html)
#import helper._
#import controllers.routes.javascript._
<!DOCTYPE html>
<html>
<head>
<title>#title</title>
<link rel="stylesheet" media="screen" href="#routes.Assets.at("stylesheets/main.css")">
<link rel="stylesheet" media="screen" href="#routes.Assets.at("stylesheets/bootstrap.css")">
<link rel="shortcut icon" type="image/png" href="#routes.Assets.at("images/favicon.png")">
<script type="text/javascript" src="#routes.Application.javascriptRoutes"></script>
<script src="#routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript"></script>
<script src="#routes.Assets.at("javascripts/bootstrap.js")" type="text/javascript"></script>
<script src="#routes.Assets.at("javascripts/message.js")" type="text/javascript"></script>
</head>
<body>
<div class="container">
<div class = "row">
<div class = "span12">
<input type = "text" id = "inputValue" value="getData"></input>
<button class = "approveButton btn btn-primary">Approve </button>
</div>
</div>
</div>
</body>
</html>
message.js
$(document).ready(function(){
$('.approveButton'). click(function(){
var value = $('#inputValue').val();
var jsonToSend = {};
jsonToSend.name = value;
var outputData = JSON.stringify(jsonToSend);
jsRoutes.controllers.Application.receiveData().ajax({
data:outputData,
contentType:'application/json',
success: function(data) {
console.log(data);
},
error: function() {
alert("Error!");
}
});
});
});
Here's the output of the curl command:
curl --header "Content-type:application/json" --request POST --data '{"name":"abx"}' http://localhost:9000/receiveData
Hello abx
Can someone please help in identifying whats wrong in the javascript file.
The expected result of the ajax call is a json object. In this case if you want to response with a plain text add dataType: 'text' to the request:
jsRoutes.controllers.Application.receiveData().ajax({
data:outputData,
dataType: 'text',
contentType:'application/json',
success: function(data) {
console.log(data);
},
error: function() {
alert("Error!");
}
});
Maybe a stupid question but what does you make think, that ajax call will be POST instead of GET ? Have you tried replacing POST by GET ?