URI Spring Encoding Issue - spring-boot

I have a query param that contains "+" sign, I encoded it and pass it to a Spring Controller but the controller interprets it as space thus failing the API.
Sample
Name = test+fetch
URI passed from browser: abc.org/fetch?name=test%2Bfetch
How Controller receives it
name = test fetch
there is nothing with test fetch and thus the API fails
Is there a way we can solve this issue, decoding the param after spring resolves it doesn't solve the issue
Edit:
Updated Controller Code
#GetMapping("fetch")
public String fetch(#RequestParam("name") String name){
return something;
}

I created an application using https://start.spring.io/ and your controller, and the encoding works as it's supposed to.
https://www.dropbox.com/s/z9rbe2gtpvzebqv/url-encoding.zip?dl=1
I think there's something before your application, may be a proxy, web server or Spring Gateway, that's decoding the parameter. Otherwise, download the app I created and prove that the problem exists.

Related

Spring RestController endpoint that consumes and produces a String value returning "HTTP Status 415 – Unsupported Media Type"

I'm trying to setup a fairly simple endpoint that takes in String and produces a String. I've simplified it down to:
#RequestMapping(value="/foo",
method = RequestMethod.GET,
consumes = MediaType.TEXT_PLAIN_VALUE,
produces= MediaType.TEXT_PLAIN_VALUE)
public String foo(#RequestBody String data) {
return data;
}
I'm testing with Postman and am just getting "HTTP Status 415 – Unsupported Media Type" back. This app is running on Spring 4.1.3. I copied this endpoint into another project I have in Spring Boot, using my same Postman request (just modified the host), and it works there. So there appears to be some issue with the version of Spring this project uses. As a work-around I created a simple wrapper entity (POJO that only consists of a single String) and changed the endpoint to consume JSON/this POJO. Does anyone know specifically why it doesn't work as above and/or know of a workaround that'll let me send and receive a plain text String with this version of Spring?

Are template engines (i.e. Thymeleaf) necessary for Spring Boot applications?

I am currently working on a Spring Boot project and I am fairly new to template engines. This will also be my first own private project with Spring Boot.
I would like to know whether it is necessary to include a template engine, such as Thymeleaf, while developing a web application with Spring Boot. I'm using PostegreSQL for the database.
I read under another post that a template engine is not needed, if the backend framework uses JSON for data exchange, because template engines are for rendering retrieved data to HTML for the client. I retrieve JSON objects from the database, can I leave template engines out of my project then?
If any more details are needed, leave a comment below.
No they aren't necessary, in fact most new projects that require web-pages are using single page applications now like Angular, React, Vue, ... over thymeleaf or jsp.
Aside from that a Spring project doesn't always need web pages, for instance when you are just creating a REST API for other applications to call on, or when you are automating things like: a mail service / printing / ... You name it.
However, when you DO want a simple solution with some pages that aren't all that dynamic or complex, pivotal / VMware does recommend to use thymeleaf (over jsp and other solutions) because it integrates easily.
I read under another post that a template engine is not needed, if the backend framework uses JSON for data exchange, because template engines are for rendering retrieved data to HTML for the client. I retrieve JSON objects from the database, can I leave template engines out of my project then?
This is partly true. Yes, Thymeleaf and alike are mostly intended to render data to HTML. They can render any text data, including JSON, but there are tools better suited for the job. On other hand it does not matter how you store the data in your database or what database you are using. You can't just skip rendering (serializing) the response so it does not matter how you store it. What matters is what you want to return as response. For HTML Thymeleaf or even JSP are suitable, but for JSON you may want to use Jackson or Gson instead.
You didn't mentioned the technology you are going to use, so for my examples I'll assume you intend to use Spring Web MVC. Lets take a look at "traditional" controller:
#Controller
public class GreetingController {
#GetMapping("/greeting")
public ModelAndView greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new ModelAndView("greeting", "greeting", new Greeting(name));
}
}
When you make GET request to "/greeting", Spring will call greeting and get the object it returns. In this case it contains the model (the data we want to render) and the view (the template file to use). Then it will try to find a view (something like greeting.html or greeting.jsp) and use template engine like Thymeleaf (or whatever else is configured) to render it (typically to HTML).
What if we want to return JSON instead? In this case we need to:
modify greeting to return Greeting instance instead of ModelAndView
Use RestController instead of Controller. This will tell Spring MVC that we want to directly serialize the object returned to JSON (or similar format) instead of using template to do that.
Here is the modified example:
#RestController
public class GreetingController {
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(name);
}
}
Spring MVC still needs some help to serialize the Greeting instance to JSON. But if you use Spring Boot and the web starter, you don't have to worry about it. It will include Jackson for you.
This is in no way exhaustive answer. As a matter of fact it skips a lot of details, but I hope nevertheless it is useful one. If you want to create REST API using JSON, this Building a RESTful Web Service guide is a good place to start. If you follow the Starting with Spring Initializr steps you'll get a project setup with only what is needed (well maybe with a bit extra but I would not worry too much about it).

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.

REST and spring-mvc

Since REST based controller methods only return objects ( not views ) to the client based on the request, how can I show view to my user ? Or maybe better question what is a good way to combine spring-mvc web app with REST, so my user always get the answer, not in just ( for example ) JSON format, but also with the view ?
So far as I understood, REST based controller would be perfectly fitting to the mobile app ( for example twitter ), where views are handled inside the app and the only thing server has to worry about is to pass the right object to the right request. But what about the web app ?
I might be wrong in several things ( correct me if I am ), since I am trying to understand REST and I am still learning.
To simplify things - you basically have two options:
1) Build Spring MVC application.
2) Build REST backend application.
In case of first option - within your application you will have both backend and frontend (MVC part).
In case of second option you build only backend application and expose it through REST API. In most cases, you will need to build another application - REST client for your application. This is more flexible application because it gives you opportunity to access your backend application from various clients - for example, you can have Android, IOS applications, you can have web application implemented using Angular etc...
Please note, that thins are not so simple, you can within one application have both REST backend and REST client etc... This is just very very simplified in order that you get some general picture. Hope this clarified a little things.
There is some additional clarification related to REST and views worth learning. From your question, I can see that you mean "view" in a sense of UI(user interface) and typical MVC usage. But "view" can mean different things in a different contexts.
So:
JSON can be considered as a view for data
JSON is a representation of the resource, just like HTML is
JSON doesn't have style (unless you are not using a browser
extension, which most the users are not using)
The browser is recognizing HTML as a markup language and applying a
style to it
Both are media types
Both JSON and HTML are data formats
Both can be transferred over the wire
This method returns a view
#RequestMapping("/home")
String home(Model model) {
return "home"; // resources\templates\home.html
}
This method Returns String
#RequestMapping(value = "/home")
#ResponseBody
public String home() {
return "Success";
}
If you annotate a method with #ResponseBody, Spring will use a json mapper to generate the response. Instead of annotating every method with #ResponseBody you can annotate your class with #RestController.
If you want to return a view, you need to annotate the class with #Controller instead of #RestController and configure a viewresolver. Bij default spring will use thymeleaf as a viewresolver if you have spring-web as a dependency on the classpath. The return type of the method is a String that references the template to be rendered. The templates are stored in src/main/resources/templates.
You can find a guide on the spring website: https://spring.io/guides/gs/serving-web-content/

Why is plus(+) decoded to space ( ) in url path with springboot rest controller?

When calling GET http://localhost:8080/things/ZhaD2lk27XQPRJtwrABltd+UTWXcbnY%2FTrpxGP7VDVo= my Spring Boot application RestController with a request handler like this:
#RequestMapping("/things/{thingId}")
public ResponseEntity<Thing> getThing(
#PathVariable String thingId) {
System.out.println("thingId=" + thingId);
...
results in the following being printed ZhaD2lk27XQPRJtwrABltd UTWXcbnY/TrpxGP7VDVo= instead of what I would have expected ZhaD2lk27XQPRJtwrABltd+UTWXcbnY/TrpxGP7VDVo=.
As you can see, the plus is being turned into a space. This should not happen with the path part, only the query part. This is why the Spring UriComponentsBuilder.build().encode() I'm using to build the URL doesn't turn the plus into %2B.
I needed to tweak the application already to get the encoded slash (/) to work. See REST Endpoint unreachable if ID in URL contains %2F for details.
I'm using SpringBoot 1.4.4.RELEASE which uses Tomcat embed 8.5.11.
I have tried calling the service from Spring RestTemplate, Postman and Chrome. Same results in all cases, the plus is turned into a space
I was able to resolve after identifying that my IDE had automagically added spring-boot-starter-undertow to the POM file. I did not exclude spring-boot-starter-tomcat from spring-boot-starter-web so I'm not sure what was happening under the covers but removing the spring-boot-starter-undertow dependency fixed the issue.

Resources