Template Development Workflow with Spring? - java

I'm working on a Spring WebMVC project that generates HTML output by using FreeMarker templates. A site controller returns a view name and a data model which is then fed into the view template.
Sample controller method (in /src/main/java/com/mycompany/controller.java):
#RequestMapping("/example")
public ModelAndView handleRequest() {
ModelAndView mv = new ModelAndView("my_tempate");
mv.addObject("my_data", "my_value");
return mv;
}
Sample template for this (which resides in /src/main/webapp/WEB-INF/views/my_template.ftl):
<title>Sample Template</title>
<p>I'm a sample template, I output: ${my_data}</p>
I package a .war file and deploy it to tomcat with mvn tomcat7:redeploy. This process takes about 4-5 seconds for my very small code base. For changes to the java code I'm fine with this compilation time. However for developing HTML templates it is a very unsatisfying workflow having to redeploy my .war file with every change.
Is it possible to set up Spring to not read template files from the .war file package but rather from the local file system while in development mode? So I could point in the source to an absolute path like /home/user/my_project/my_template.ftl that is parsed on every site request.

Related

Subfolders in SparkJava's static files folder not mapped

I'm doing a GUI in Angular which is calling a REST-api written in SparkJava (JavaSE). Everything will be running on the same machine.
The GUI was originally written in swing but I'm rewriting it in Angular to get a more modern touch.
Problem:
When the application starts everything seems to be loaded as expected. When I open the web page in a browser I get an INFO-message in the Java-console stating spark.http.matching.MatcherFilter - The requested route [/sv/assets/images/image1.png] has not been mapped in Spark for Accept: [image/webp,*/*], among other similar messages.
The Angular files are located in src/main/resources/public. There are a few subfolders with content, see screen shot.
The backend is served as it should, but the frontend files can't be loaded properly in the browser. HTML/JS/CSS seems to be loaded correct, but images and other files in assets folder can't be loaded.
Can this be solved? Or do I have to put all files in the root directory? I found nowhere all static files in SparkJava have to be located in the same folder (meaning, no subfolders).
My setup:
Spark.port(4567);
Spark.staticFiles.location("/public");
// simple rest API to serve some data
Spark.get("/labels/getall", "application/json", new Route() {
#Override
public Object handle(Request rqst, spark.Response rspns) throws Exception {
Labels l = LabelReader.getLabels();
Gson gson = new Gson();
return gson.toJson(l);
}
});
File tree:
Java console messages
Browser output

How to configure Thymeleaf template location

I want to use Thymeleaf in a Spring Boot 2.1.5 based application. But I do not need it to create html output for a RestController. Instead of that I want it to create html files that the application can store on disk.
Because of this I create two beans templateResolver and templateEngine like the docs describe. The templates are stored in the same location I would use for the RestController: src/main/resources/templates. One for example is called index.html.
But no matter which path I configure (with or without classpath) I get the same error message:
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("classpath:/resources/templates/");
templateResolver.setSuffix(".html");
java.io.FileNotFoundException: class path resource
[resources/templates/index.html] cannot be opened because it does not
exist
How do I need to configure the path to make it work a) inside STS and b) inside the created jar ?
An alternative to solving this problem would be using spring-boot-starter-thymeleaf instead and "grabbing" its generated output instead of exposing it via the embedded Tomcat but I do not know how to get this to work:
#GetMapping("/noneedforthis")
public String getIndexFileContent(#RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "index";
}
I checked both the local target directory of my Eclipse workspace and the jar created by running maven install: instead of resources/templates the templates are stored in templates.
Shortening the path in my code helped and now Thymeleaf can find the templates.
Using the Spring Boot Starter for Thymeleaf would still be an interesting alternative but so far I have not found an approach.

Spring Boot resources not found

Ok, I developed a small spring boot website using thymleaf and now realized that I can't use the webapp folder if I want to package everything with the maven plugin.
To fix this I moved all my resources to src/main/resources. However, I keep getting FileNotFoundExceptions when I try to display any site (simple RequestMapping returning a String):
This is the error I get:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/index.html]
at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:157) ~[spring-web-5.0.0.BUILD-SNAPSHOT.jar:5.0.0.BUILD-SNAPSHOT]
at org.thymeleaf.spring5.templateresource.SpringResourceTemplateResource.reader(SpringResourceTemplateResource.java:103) ~[thymeleaf-spring5-3.0.3.M1.jar:3.0.3.M1]
at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:223) ~[thymeleaf-3.0.3.RELEASE.jar:3.0.3.RELEASE]
... 75 common frames omitted
And then I get the same error again when Spring tries to load my error page.
Full http://pastebin.com/raw/Csw5akHJ
Explorer
(Yes I know that only the static folder is available. Good enough for testing.)
Can anyone help me? This is getting a bit frustrating.
If you are using Thymleaf as Template Engine you should add all .html files inside resources/templates
i am not sure if this is your problem but normally i would put all the html pages inside templates directory under resources and all js and css files under static directory.
by doing so js and css files can easily accessed. for eg if i have css directory and test.css inside it. i can simply access it doing
so coming to your problem on my controller i will return pages like this.
#RequestMapping(value="/viewusers",method = RequestMethod.GET)
public String viewUsers(){
return "users/viewusers";
}
in above sample i have viewusers.html under users directory. my users directory is inside templates directory.
OK, I made some headway. While it works fine if I use the default template Engine It stops working as soon as I start using the Thymeleaf one. Apparently the default template Engine can handle classpaths automatically while I needed to switch from SpringResourceTemplateResolver to ClassLoaderTemplateResolver if I want to use thymeleaf.
So far it looks like everything is working fine. Halleluja!

How to start with spring mvc and install dependencies

I am new to spring needed to know how to start and how to import dependencies in spring mvc. i am starting a project for web application possible with single page application
Best possible website to start is https://start.spring.io/ . On this select dependency package you need and get a kick start for your project. You can also install some dependency later as per your need in pom.xml file.
To start from scratch, move on to Build with Gradle.
If you know basics and want code template, do the following:
Download and unzip the source repository or clone it using Git: git clone https://github.com/spring-guides/gs-serving-web-content.git
cd into gs-serving-web-content/initial
Jump ahead to Create a web controller.
When you’re finished, you can check your results against the code in gs-serving-web-content/complete.
Build with Gradle
First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Gradle is included here.
Create the directory structure
In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello on *nix systems:
└── src
└── main
└── java
└── hello
Create a Gradle build file
Below is the initial Gradle build file.
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'gs-serving-web-content'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-devtools")
testCompile("junit:junit")
}
The Spring Boot gradle plugin provides many convenient features:
It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
It searches for the public static void main() method to flag as a runnable class.
It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.
**Create a web controller**
In Spring’s approach to building web sites, HTTP requests are handled by a controller. You can easily identify these requests by the #Controller annotation. In the following example, the GreetingController handles GET requests for /greeting by returning the name of a View, in this case, "greeting". A View is responsible for rendering the HTML content:
src/main/java/hello/GreetingController.java
package hello;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
#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";
}
}
This controller is concise and simple, but there’s plenty going on. Let’s break it down step by step.
The #RequestMapping annotation ensures that HTTP requests to /greeting are mapped to the greeting() method.
The above example does not specify GET vs. PUT, POST, and so forth, because #RequestMapping maps all HTTP operations by default. Use #RequestMapping(method=GET) to narrow this mapping.
#RequestParam binds the value of the query String parameter name into the name parameter of the greeting() method. This query String parameter is not required; if it is absent in the request, the defaultValue of "World" is used. The value of the name parameter is added to a Model object, ultimately making it accessible to the view template.
The implementation of the method body relies on a view technology, in this case Thymeleaf, to perform server-side rendering of the HTML. Thymeleaf parses the greeting.html template below and evaluates the th:text expression to render the value of the ${name} parameter that was set in the controller.
src/main/resources/templates/greeting.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
Developing web apps
A common feature of developing web apps is coding a change, restarting your app, and refreshing the browser to view the change. This entire process can eat up a lot of time. To speed up the cycle of things, Spring Boot comes with a handy module known as spring-boot-devtools.
Enable hot swapping
Switches template engines to disable caching
Enables LiveReload to refresh browser automatically
Other reasonable defaults based on development instead of production
Make the application executable
Although it is possible to package this service as a traditional WAR file for deployment to an external application server, the simpler approach demonstrated below creates a standalone application. You package everything in a single, executable JAR file, driven by a good old Java main() method. Along the way, you use Spring’s support for embedding the Tomcat servlet container as the HTTP runtime, instead of deploying to an external instance.
src/main/java/hello/Application.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#SpringBootApplication is a convenience annotation that adds all of the following:
#Configuration tags the class as a source of bean definitions for the application context.
#EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
Normally you would add #EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
#ComponentScan tells Spring to look for other components, configurations, and services in the the hello package, allowing it to find the controllers.
The main() method uses Spring Boot’s SpringApplication.run() method to launch an application. Did you notice that there wasn’t a single line of XML? No web.xml file either. This web application is 100% pure Java and you didn’t have to deal with configuring any plumbing or infrastructure.
Build an executable JAR
You can run the application from the command line with Gradle or Maven. Or you can build a single executable JAR file that contains all the necessary dependencies, classes, and resources, and run that. This makes it easy to ship, version, and deploy the service as an application throughout the development lifecycle, across different environments, and so forth.
If you are using Gradle, you can run the application using ./gradlew bootRun. Or you can build the JAR file using ./gradlew build. Then you can run the JAR file:
java -jar build/libs/gs-serving-web-content-0.1.0.jar
If you are using Maven, you can run the application using ./mvnw spring-boot:run. Or you can build the JAR file with ./mvnw clean package. Then you can run the JAR file:
java -jar target/gs-serving-web-content-0.1.0.jar
The procedure above will create a runnable JAR. You can also opt to build a classic WAR file instead.
Logging output is displayed. The app should be up and running within a few seconds.
Test the App
Now that the web site is running, visit http://localhost:8080/greeting, where you see:
"Hello, World!"
Provide a name query string parameter with http://localhost:8080/greeting?name=User. Notice how the message changes from "Hello, World!" to "Hello, User!":
"Hello, User!"
This change demonstrates that the #RequestParam arrangement in GreetingController is working as expected. The name parameter has been given a default value of "World", but can always be explicitly overridden through the query string.
Add a Home Page
Static resources, like HTML or JavaScript or CSS, can easily be served from your Spring Boot application just be dropping them into the right place in the source code. By default Spring Boot serves static content from resources in the classpath at "/static" (or "/public"). The index.html resource is special because it is used as a "welcome page" if it exists, which means it will be served up as the root resource, i.e. at http://localhost:8080/ in our example. So create this file:
src/main/resources/static/index.html
<!DOCTYPE HTML>
<html>
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Get your greeting here</p>
</body>
</html>
and when you restart the app you will see the HTML at http://localhost:8080/.
how to import dependencies in spring mvc?
Spring MVC or not, to manage dependencies you can use any of the Java packaging tools like Gradle or Maven (there are other option too , like ivy or ANT from ancient world :) )
How to start
https://start.spring.io/ Start any of the spring project from this website, select the dependencies you want. When you click on generate it will download a zip file which contains a project (gradle or maven) with all the dependencies you selected. And then, later you can add or change dependencies by editing your build.gradle (if you have selected gradle) or pom.xml (if you have selected maven).

Java MVC project in Spring Tool Suite additional files

I'm learning to make Java MVC project using Spring Tool Suite tool.
The path to make new project is:
File->New->SpringLegacyProject->Spring MVC Project.
My question is: which directory I have to use to add additional not-Spring files and where and what do I have to type for Spring files to see them?
For example:
css files - where to put and how to make jsp views see them, will 'link rel="" 'tag be enough?
properties files used to specify database connection or to specify messages for ReloadableResourceBundleMessageSource. In this case, do I have to create bean for this class in root-context.xml?
Thanks.
You should probably use Spring Boot (i.e. use File->New->Spring Starter Project and select Web as a starter. Place your web resources under src/main/resources/static folder. They are picked up automatically from that folder.
You should try an example project: File -> New -> Import Spring Getting Started Content and then pick "Serving Web Content" from the list.
Try some DB getting started content example to get the answer for the second part of your question.

Categories