Spring boot, tomcat, rest api 404 - spring

I am using Kotlin + Gradle and trying to build a war file to deploy on Tomcat. My application is from the https://start.spring.io plus a simple controller and build the war file using ./gradlew bootWar
#SpringBootApplication
class ServletInitializer : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(DemoApplication::class.java)
}
}
#RestController
class TomcatController {
#GetMapping("/hello")
fun sayHello(): Collection<String> {
return IntStream.range(0, 10)
.mapToObj { i: Int -> "Hello number $i" }
.collect(Collectors.toList())
}
}
when I try to access it I get
Type Status Report
Message The requested resource [/demo-0.0.1-SNAPSHOT/hello] is not available
Description The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
I am super stuck. What am I doing wrong? If I add a html file to the src/main/webapp/index.html it shows up for some reason only the rest api can't be reached.

Spring Boot applications come with a built in Servlet. You are probably already using this feature when launching the application inside your IDE.
This basically means that you can just run your .jar file on any web server and it will be ready to go without setting up an extra tomcat instance.
However, if you want to build a Spring Boot application as a war file and deploy it to an external tomcat, you need to follow some extra steps as explained in this article.

Assuming from what you posted so far: the path that is returned shows another route before your actual controller route "/demo-0.0.1-SNAPSHOT/hello" is this "/demo-0.0.1-SNAPSHOT" the path that your application runs on ? If not it should be included in your controller (assuming you havent set it elsewhere for e.g. in your application.properties).
for e.g. http://localhost:8080/ would be the basepath and either http://localhost:8080/demo-0.0.1-SNAPSHOT/hello or http://localhost:8080/hello would point to your controller. Also your startup logs (for Tomcat and Spring) might give away more about the issue.

Related

Zuul Proxy does NOT work on Tomcat vai SpringBootServlet

I'm seeking for a help with an issue I'm facing with Zuul which is not working on Tomcat being packaged into WAR.
Standalone it works perfectly well, but when I change packaging to war and deploy to Tomcat - requests does not seem to reach Zuul.
I have extended SpringBootServletInitializer and overridden configure() method, but that does not help.
Note: please do NOT advise me to run SpringBoot standalone with embedded Tomcat - that does not work as I need to incorporate an API gateway into existing infrastructure set up. In other words I need to implement a gateway given a boundary condition - it has to be deployed on Tomcat application server.
#SpringBootApplication
#EnableZuulProxy
public class GatewayApplication extends SpringBootServletInitializer {
...
#override
protected StringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(GatewayApplication.class);
}
}
application.yml
zuul:
routes:
freebeer:
path: "/beer/**"
url: "https://freedom.com:443"
default:
path: "/**"
url: "http://landing.com/"
It works perfectly fine when I'm running standalone app with embedded Tomcat e.g.:
- request to http://localhost:8080/ is nicely redirected to http://landing.com/
- as well as ..:8080/beer is nicely redirected to freedom.com
But in case of WAR deployed to Tomcat - nothing works:
- request to http(s)://tomcat.intranet.com:12345 welcomes me with message that nothing is there and suggests to add web content
- request to http(s)://tomcat.intranet.com:12345/beer gives me 404 with message that origin server did not find a current representation for the target resource or that it's not willing to disclose that one exists
Looks like I'm missing something very obvious. But I've run out of patience to figure it out and calling for help :)
Resolved. Requests were simply sent to wrong context - to app server root instead of web app specific. I solved it by naming war as ROOT.war

Spring Boot - How to add custom controller logic before user accesses static files

I'm working on a Spring Boot project, where some static contents are served from the src/main/resources/static directory.
My goal is that whenever a user tries to access static contents that end with a certain suffix (e.g. ".xlsx"), the request is intercepted and I check to see if the user has the right permission using Spring AOP, and reject the request if necessary. I've got the AOP part working in other scenarios, but not in this scenario yet.
Currently I've tried something like the following, but the method isn't being invoked upon accessing a file of ".xlsx" suffix:
#RequestMapping("/*.xlsx")
public void checkPermission() {
}
Can this be done without using Spring Security? Thanks in advance.
Have you tried Filter interface? much more available.
LINK: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/OncePerRequestFilter.html
Using this you can easily parse the request before even it reaches the controller and add you business logic/validation to it.

Springboot REST endpoints with Alfresco Process Services (Activiti)

I have installed Alfresco Process Services on my local machine. I have also created a springboot project to write custom listeners like Task listener or execution listeners. These listeners are working fine. I create a jar file and put it into webapp\activiti-app\WEB-INF\lib folder.
Now I want to add REST endpoints in my application so that external users can directly take an action on task.
I added the following class beside my main application class which has the main method.
#RestController
#RequestMapping("/api2")
public class WorkflowController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", defaultValue="World") String name) {
return "Hello from " +name;
}
}
The issue is when I try to access the endpoint via any of the below URL it gives me 404 error.
http://localhost:8081/activiti-app/api2/greeting
OR
http://localhost:8081/api2/greeting
Please help
To access the URL publicly you need to start your mapping with /enterprise. APS requires this to distinguish between public and private rest APIs, so your #RequestMapping("/api2") should be #RequestMapping("/enterprise/api2") which should then be accessible with http://localhost:8081/activiti-app/api/enterprise/api2/greeting. refer the developer series for a detailed example.

Spring Boot code, workflow is -> upload file - then tamper with file - download the file

I am doing the following tutorial at spring.io (https://spring.io/guides/gs/spring-boot/) and this is my first spring-boot application, I am a java-developer. I am using the Maven-approach and deploying it as a stand-alone jar (not relevant to the use-cases really).
The question about the code has to do with structuring and boils down to the question "where should I put in my 'business-logic'?". The logic that I would like to apply concerns the following 2 use-cases.
I want to transform 2 columns in the uploaded csv-file (or excel-file) and let the user download the 'transformed'-file.
If the user uploads an image file, I want to check if there are any EXIF-Tags (such as coordinates ++ ) in the image - and if there is, I would like to store that information in a database.
Or should I take a broader look at Spring MVC or similar technologies when it comes to my use-cases ?
best, Ingo
Right now I am running Ubuntu 18.04 and using java 1.8, maven 3.0.5 and Netbeans 8.2.
To answer your question:
"where should I put in my 'business-logic'?"
You basically want your Controller to handle your requests only and let another class handle the logic, which is a Service in Spring terms.
You would have a file MyService.java similar to this:
#Service
class MyService {
public MyData handleCSV(<your parameters>) {
return ...
}
}
In your Controller you can inject your service and simply use it:
#Controller
class MyController {
#Autowired
private MyService myService;
}
That's it. Anywhere in this controller, you can call the myService instance.

Environment Configuration Spring Boot

Created a Spring Boot application that will need to migrate from "Local Dev" to "Test", "QA" and "Prod" environments.
Application currently uses a "application.properties" for database connectivity and Kafka configuration.
I am wanting to deploy to "Test" and realized that the properties will not work for that enviornment. After reading the ref docs, it looks like I can simply copy the application.properties file and add a new one application-test.properties, so on, and then run the standalone jar with a -Dspring.profiles.active=test and that seems to work.
But by the time I am done, that means I h ave 4 different appliction-XXXXX.properties files in the jar which may or may not be bad. I know the ultimate configuration would be to use Spring Config server, but right now we are not there with regards to this.
Can anyone validate that using multiple properties files is viable and will work for a bit, or if I am looking at th is all wrong. I do not want to have configuration on the servers in each environment, as I am thinking these mini-services should be self-contained.
Any input would be appreciated.
in a word, your configuration file should be outside your source code.
#PropertySource(value = {"classpath:system.properties"})
public class EnvironmentConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Let's say it's named "system.properties", which will be uploaded to server at deployment stage under your application classpath.

Resources