I want to separate Back-End and Front-End(HTML Pages) machines.The back-end will be developed by Spring-Boot. How can return View in controllers to Front-End machine instead of "resources/template" in Back-End(Spring-Boot--->Apache Tomacat) machine?
For example :
#Controller
public class GreetingController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
I want to put "greeting" view in another server (Front-End).
You didn't disclose which templating technology are you using (e.g. JSP, Thymeleaf, ...), but either way Spring needs to inject your variables from model into HTML templates.
AFAIK, there is no way to host views in one JVM and controller filling it on other JVM. You could extract your views into separate JAR, but it would need to be hosted on same Servlet container at the end of the day.
If you want true separation of client and server, investigate templating on client (Single Page Applications) and using just AJAX for fetch the data from REST back-end.
You can start two servers, one for backend and the other for frontend. The two would be communicating via REST call. The Backend server will give the data to frontend server, which will collect it and send it to html templates in the frontend server. The template engine integration would save you time in getting things done. Springboot has good integration with Thymeleaf so I would recommend you to use the same.
It's actually quite simple after you have the prototype ready. I have made the prototype for frontend and backend separated springboot applications. The template engine used here is thymeleaf, database is mysql and language is java. You can remove the unneeded part and start with your work!
You may need to implement a/the WebMvcConfigurerAdapter interface.
This is a code sample:
#Configuration
public class StaticResourceConfiguration extends WebMvcConfigurerAdapter {
#Value("${spring.thymeleaf.prefix}")
private String thymeleafTemplatePath;
#Value("${node_modules.path}")
private String nodeModulesPath;
public void addResourceHandlers(ResourceHandlerRegistry registry){
if (thymeleafTemplatePath != null && !thymeleafTemplatePath.isEmpty()){
if (!registry.hasMappingForPattern("/**")) {
registry.addResourceHandler("/**")
.addResourceLocations(thymeleafTemplatePath);
}
}
if (nodeModulesPath != null && !nodeModulesPath.isEmpty()){
if (!registry.hasMappingForPattern("/node_modules/**")) {
registry.addResourceHandler("/node_modules/**")
.addResourceLocations(nodeModulesPath);
}
}
}
}
The following code is for a configuration variable in a property file.
This example has a Windows file path pattern. You may need to change the pattern for your environment.
spring.thymeleaf.prefix=file:///C:/Users/young.k.jun/workspaces/separated-front-end/front-end/src/
node_modules.path=file:///C:/Users/young.k.jun/workspaces/separated-front-end/front-end/node_modules/
I made a sample project to separate front-end and back-end workspace so as not to conflict with their work directories.
Please refer to this link. You can find a GitHub link on that page.
It's possible to do that with REST-Web-Service but the goal from Thymeleaf isn't to work alone as frontend App. If you absolutly need to have a separated frontend App you should user any moderne js framework such as Angular/React/Vue and use spring boot for rest api.
Related
Problem
Very short: I want to create Spring Shell, but as a web application.
I want to create a web-application (preferably using Spring Boot), where the frontend (ReactJS) looks like a terminal (or shell), and the backend processes inputted commands. Look at https://codepen.io/AndrewBarfield/pen/qEqWMq. I want to build a full web app for something that looks like that.
I want to build a framework, so that I can develop backend commands without knowing anything about the frontend/web application structure. I basically want to instantiate a "Terminal" object, where I give some kind of input-stream and output-stream. This way I can program this Terminal based on my given interfaces and structure, without the need of setting up all kind of front-end stuff.
A good summary of the question would be: how to send all keyboard inputs to the backend, and how to send all output to the frontend?
The reason I want to create a web application, is because I want it to be available online.
What I tried
I think the way of reaching this is using websockets. I have created a small web application using this (https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react) tutorial, without the security part. The websocket part is almost suitable, I just cannot get an "input" and "output" stream-like object.
#Controller
public class WebSocketController {
private SimpMessagingTemplate simpMessagingTemplate;
#Autowired
public WebSocketController(SimpMessagingTemplate simpMessagingTemplate) {
this.simpMessagingTemplate = simpMessagingTemplate;
}
#MessageMapping("/queue")
#SendToUser("/topic/greetings")
public Greeting greeting(HelloMessage message, #Header(name = "simpSessionId") String sessionId) throws Exception {
System.out.println(sessionId);
// Do some command parsing or whatever.
String output = "You inputted:" + HtmlUtils.htmlEscape(message.getName());
return new Greeting(output);
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
return headerAccessor.getMessageHeaders();
}
Now with this code, you can parse a command. However, it doesn't keep any "state". I don't know how it works with states and websockets.
I saw you had this Spring Sessions + WebSockets (https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-websocket.html), but this is not really what I want.
I can send a message from the backend to the frontend by using this code:
simpMessagingTemplate.convertAndSendToUser(sessionId, "/topic/greetings", "hey", createHeaders(sessionId));
However, I want my terminal to be able to wait for input commands from the user. Seems like a stretch, but does anybody know how to achieve this?
What I sort of want
I basically want other people to program to this interface:
public interface ITerminal {
void setInputStream(Object someKindOfWrapperForTheInput);
void setOutputStream(Object someWrapperOfSimpMessagingTemplate);
void start();
}
When somebody opens the web application, they get a dedicated terminal object (so a single connection per user). Whever somebody enters a command in the frontend application, I want it to be received by the terminal object, processed, and response outputted to the frontend.
Reasons for doing this
I really like creating command-line applications, and I don't like building frontend stuff. I work as a software engineer for a company where we build a web application, where I mostly program backend stuff. All the frontend part is done by other people (lucky for me!). However, I like doing some projects at home, and this seemed cool.
If you have any thoughts or ideas on how to approach this, just give an answer! I am interested in the solution, using the SpringBoot framework is not a requirement. I ask this question using Spring Boot and ReactJS, because I have already built applications with that. A lot has been figured out already, and I think this probably exists as well.
The only requirement is that I can achieve this with Java on a tomcat-server. The rest is optional :)
Unclear?
I tried my best to make my story clear, but I am not sure if my purpose of what I want to achieve is clear. However, I don't know how to formulate it in such a way you understand. If you have any suggestions or questions, dont hesitate to comment!
If the only thing you want is a Live Spring shell that shows up in the browser it's fairly simple, all you need is to expose a standard WebSocket via the WebSocketConfigurer, then add a WebSocketHandler that executes the command and then returns the resulting String as a TextMessage.
Firstly the Socket configuration that allows clients to connect to the 'cli' endpoint
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(cliHandler(), "/cli").setAllowedOrigins("*");
}
#Bean
public CLIWebSocketHandler cliHandler() {
return new CLIWebSocketHandler();
}
}
Then the WebSocketHandler that executes the command. I recommend that for every #ShellMethod you specify the return type as String, don't use logging or System writes as they won't be returned during the evaluation.
#Component
public class CLIWebSocketHandler extends TextWebSocketHandler {
#Autowired
private Shell shell;
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String result = shell.evaluate(() -> message.getPayload()).toString();
session.sendMessage(new TextMessage(result));
}
}
You can use an extension like Simple WebSocket Client to test it, by going to ws://localhost:port/cli
This is the most basic solution, adding features like security should be easy after this. Notice that I don't use STOMP, because you probably want to isolate users. But it can work alongside STOMP based endpoints, so you can have pub-sub functionality for other parts of the project.
From the question I sense that answer you'd like is something that involved Input and OutputStreams. You could possibly look into redirecting the output of Spring Shell to a different stream then have them forwarded to the sessions but it's probably much more complicated and has other trade-offs. It's simpler to just return a String as the result, it looks better in print outs anyway.
I am having some trouble understanding this. Can someone help me better understand this?
MVC
Model --> Java- Spring Framework
View ---> templating language(JSP velocity) & Javascript
DB --> SQL
Q-1)
Now, When I open a particular page, I can't visualize the flow. I've read about DAO, controller , service etc and I understand them individually but I am really confused when I club all together what's the order of execution? Whats the flow exactly ? Is it that first the view is loaded then it sends JS request to fetch the necessary data from backend and then the controller and service are invoked and the DAO queries the db? Then how does the API come into picture? DAO deals with the API?
Q-2)
Why do we need xyz.properties? I have removed a module from my page. If I remove a particular js file(related to that module) from the scripts.properties, then ideally that js should not get executed at all right? Then still why would I see the api call to fetch the data related to that module? I don't see the module but I sure see the api call. Why is that?
DB doesn't enter in MVC model. And you're forgetting a principal element in your analysis: the Controller. The flow goes like this:
Client performs a request to an URL
The application server gets the URL and passes the handling to the web application.
The web application using Spring MVC will handle the URL processing to the Controller: DispatchServlet, which is a Servlet.
The DispatchServlet will try handle the URL. If there's an URL mapping, then it will pass it to the class (mapped in the spring.xml config or decorated with #Controller annotation).
This controller (which in fact is part of the model) will handle the request. It will call services, daos, etc (Model) and return the necessary data to complete the response to the DispatchServlet.
The DispatchServlet will finish the request handling and, in the end, will generate the results e.g. a text/json response, or it will forward to a JSP file (View).
For question two, I never have used such scripts.properties file, so I don't know what you're talking about. Usage of a properties file is to store application properties that should not change until an application redeploy. They have 3 main advantages:
They can be easily manipulated by human users. It's no rocket science to add, edit or remove values.
Since it is a plain text, it's easier to version using a version control system like SVN, Git or another of your preference.
It provides a faster access since it is usually in the same disk as the application, so there's no much time penalty when accessing to its contents compared to a database configuration. But since it is in disk, it still has a disadvantage against RAM access only.
In simple layman's term, MVC explained in pictorial form
(inputing data) (data related part) (display rendering)
-request mapping -classes -JSP (Script,CSS,HTML)
-request param -interface -velocity
Controller ------------->Model--------------->View
||
\/
(data processing logic) (access to Databse)
-optimization -JDBC
-business logic -SQL
Service--------------------->DAO
I have a Java web app that runs in JBoss. I'm adding a new web page for applying for a job, using AngularJS, and I'd like it respond to this (RESTful) URL: /job/<job id>/apply
Since I'm new to Angular, I'm trying to figure out how to route the user's request of a URL like:
GET /job/1/apply (where "1" is the job id)
to a static HTML page in my web app, like src/main/webapp/job/apply.html. My plan is to have an ng-app and ng-controller specified in the apply.html template, which will call back to the server to fetch JSON to render in the view.
So how do I configure routing in my Java-based web app, so that requesting /job/1/apply yields /job/apply.html, and my controller JS code that's loaded by apply.html has easy access to the URL parameter "1"?
I've come up with several potential ways of accomplishing this, but none of them seem very simple or straightforward:
Use Spring MVC, write an #Controller that listens to the RESTful URL, and forwards the request to apply.html. (I'm not even using Spring MVC in this web app... yet.)
Use Spring MVC and the <mvc:resources> or <mvc:view-controller> element, to map the requested URL to the HTML page.
Use a web filter to rewrite the incoming URL to /job/apply.html.
Give up on using a RESTful URL, make the job ID a query param instead, and rename my apply.html to just index.html (so it gets picked up automatically). E.g. the user requests /job/apply?jobId=1, which maps to webapp/job/apply/index.html.
The thing I'm most uncertain about is whether the job ID in the request URL will be available to my angular controller code, in order to fetch data from the backend about that job.
Redirect every request server-side to index.html when not requesting a file and use ng-route (http://docs.angularjs.org/api/ngRoute.$route) to load the correct template with something like
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/job/:jobid/apply', {
templateUrl: '/job/apply.html'
}).
otherwise({
redirectTo: '/'
});
}
]);
If you can make use of the "html5 mode" of ngLocation (http://docs.angularjs.org/guide/dev_guide.services.$location) that would be even cleaner for the end user.
Is it possible to run GWT application from web service REST?
#Path("/main")
public class RestService {
#GET
#Path("{name}")
public Response getUserByName(#PathParam("name") String name){
// return Response.status(200).entity("My name is " + name).build();
}
}
What is important for me, the URL which calls REST, must not be changed after GWT will run. So when the browser go to localhost:8080/application/main/adam, the REST runs and calls the GWT application which shows message box with My name is adam. After that, I can sill see the same URL in the browser.
Maybe I should explain the reason of my requirements.
I want to create application where the end-user will use only the URLs, example:
localhost:8080/application/somecommand/somedata
localhost:8080/application/anothercommand/anotherdata
No windows, no forms, only URLs.
Yes, it is possible. Just serve the HTML page with your GWT app.
If you can deal with Urls Like this:
localhost:8080/application#somecommand/somedata
localhost:8080/application#anothercommand/anotherdata
It is just the GWT History-API
Background
We have several clients, some is native as iPad and Android, other is html clients, like web and SmartTv.
We have a centralized web project that serve typical assets to all this clients, like icon, favicon, fonts and so on. In this way we can maintain assets in one place.
Problem
I now want to serve the messages property file, that is not public in the war file, to the JavaScript and the native clients.
Is there any good suggestion how to provide this messages public and in a proper format that fit the different clients?
If I understand correctly, you want to use the #{i18n/} tag as shown here. It will give you a javascript method that provides I18N translation of keys as defined in the messages file.
One solution in Play! is to serve the messages to the public as json:
public class AssetsController extends Controller{
public static void getMessages(){
String locale = params.get("locale");
if(locale == null){
locale = Lang.get();
}
System.out.println(locale);
Properties messages = Messages.all(locale);
renderJSON(messages);
}
}