I need a resource handler to serve static resources. I know that to serve static resources I should place them in META-INF/resources. I want to add resource handler with URL path patterns and configure the locations to serve static resources.
I would suggest looking into Quarkus' Reactive Routes.
They essentially allow you to register a Vert.x Route in a more declarative way.
In the implementation of your Route, you can do whatever you like.
For reference, this is how Vert.x's serves static resources.
Based on previous answer https://stackoverflow.com/a/68347961/8284722, a solution can be:
#ApplicationScoped
public class StaticContentDeclarativeRoute {
#Route(path = "/static/*", methods = Route.HttpMethod.GET)
void staticContent(RoutingContext rc) {
StaticHandler.create(FileSystemAccess.RELATIVE, "content/").handle(rc);
}
}
and consider the path can also be absolute using FileSystemAccess.ROOT
Related
I'm looking to define /api as the root context for all my #RestControllers and don't want to specify it for each of them.
For instance, I would like to write #RestController("/clients") instead of #RestController("/api/clients") and make my request mappings available at /api/clients but have my static resources (in /main/resources/static) still served at /**.
So, setting server.servlet.contextPath=/api in application.properties is not a solution for my use case because the static resources will be served at /api, which I don't want.
In brief, I would like to have the same feature as JAX-RS #ApplicationPath("/api") in Spring Web MVC, is this possible?
One of the possible solution(work around) is to use Parent Class with mapping
#RequestMapping(path="/api")
abstract class BaseController{
....
}
Other controllers can extend it
class OtherController extends BaseController {
#RequestMapping(path="/clients")
public ....clients(....){
.....
}
}
Please note that #RequestMapping will get overridden if you place it on top of any child class. Like explained here and here
Set the context root you want by using spring.mvc.servlet.path config into your application.properties.
e.g:
spring.mvc.servlet.path=/api/v1
In Spring we've got #ExposesResourceFor annotation which can link our resource with other resources. Thanks to this our Value objects (representations) can know nothing of the actual resources.
Is there a way to do it in JAX-RS? I'm using Dropwizard with Jersey and Jackson and all I see is #InjectLinks annotation which I can use in a value object like this:
public class UserGroup {
#JsonProperty
public String name;
#InjectLinks(GroupsResource.class)
public URI myResource;
public UserGroup(String name){
this.name = name;
}
}
But unfortunatelly my Value Objects should know nothing about Resources, so I'm asking can I do such linking on the level of resources - link in spring-hateoas in controllers, as mentioned above.
With #InjectLinks, you don't have to declare the links in your model class. You can create a "wrapper" representation class, as shown in declarative-linking from the Jersey examples (though this solution is not really on the resource class level as you wish).
Another possible solution (rather than declarative linking) is to use the JAX-RS 2.0 Link class, and do the linking programmatically (with no ties to the Jersey implementation/annotations). You can either add the links to your response headers, as see here, or add Links to you model classes, as seen here (or use the wrapper class for this also, so as to not to invade your model classes)
Some Resources
Declarative Hyperlinking
Using Link for headers
I have a lot of Controllers that are extends one base Controller which has a static contructor with ResourceBundle generation:
static {
resources = ResourceBundle.getBundle("com.resource.Resources");
}
I need it because app's logic based on locale, not only views.
In addition I have a CookieLocaleResolver that resolves the current locale from the cookie.
The problem is that base controller's static constructor code executes before the CookieLocaleResolver's resolveLocale method so I am always receive a system's default locale at ResourceBundle and not the current one.
How can I solve it? Thank you
That's because the static block is executed at the class initialization time. You need to load the ResourceBundle when the controller is called. I would suggest you here to define your controller as a prototype and use InitializingBean to load the ResourceBundle.
public class MyController implements InitializingBean {
private ResourceBundle resources;
public void afterPropertiesSet() {
resources = ResourceBundle.getBundle("com.resource.Resources");
}
}
A better way would be to use the ResourceBundleMessageSource and not use the ResourceBundle directly. If you can, that would be much easier since you don't have to manage the ResourceBundle directly.
I hope that will help you.
[Edit]
The Spring MessageSource provides methods to resolve messages with parameters. If you define a MessageSource in your application, you will be also able to access the same messages in the view (JSP page for instance). At last, from the design, that is better if the controller doesn't have a direct reference on the resource bundle, this way your labels/messages are managed in a single place (in your Spring config when you declare the MessageSource).
I'm currently working on a spring based web application and have a special requirement that seems not (at least not out of the box) be provided by spring MVC. The application serves data for multiple users each organized in their own "company". Once a user has logged in, I'm able to identify to which company he belongs to.
The application itself is built with multiple "modules", each with it's own domain objects, DAO, Service and Controller classes. The idea behind this concept is that I can for example extend a certain controller class (let's say to use a different service class) based upon the user and here is my problem.
Since i do not want to change my request paths for certain users, I'm currently looking for a way how to serve a request issued on a certain request path with different instances of a controller based upon the user issuing the request.
I came up with the idea to attach a HTTP Header Field for the company
Example:
X-Company:12345
and have my controllers configured like this:
#Controller
#RequestMapping(value="/foo/")
public class FooController {
// ...
}
#Controller
#RequestMapping(value="/foo" headers="X-Company=12345")
public class SpecialFooController extends FooController {
// ...
}
However this is not possible, since spring MVC treats each header (except Content-Type and Accept) as a kind of restriction, so in my case it would handle all requests with the FooController instead of the SpecialFooController unless i add a "headers" restriction on the FooController as well, which is not practicable.
Is there some way how to customize this behaviour or some direction one could point me to look for? Or maybe someone has another idea how to achieve this. It'll be highly appreciated.
Thanks!
I'am not sure but I think you can do this with HandlerMapping. Have a look at the documentation
To take your own suggestion, you can use the #RequestHeader annotation in your controller methods:
#Controller
public class MyController {
#RequestMapping("/someAction")
public void myControllerMethod(#RequestHeader('X-Company-Id') String companyId) {
}
}
Or you could use #PathVariable:
#Controller
public class MyController {
#RequestMapping("/{companyId}/someAction")
public void myControllerMethod(#PathVariable("companyId") String companyId) {
}
}
Using this approach would mean that it is in fact different URLs for each company, but if you can set the company id header, I guess you also can suffix the URLs with the company id.
But there are also other possibilities. You could write an interceptor that puts the company id in a session or request variable. Then you wouldn't have to add the annotation to every controller method. You could also use a subdomain for each company, but that wouldn't look too pretty if the company id is a random alphanumeric string. E.g: companyone.mydomain.com, companytwo.mydomain.com
Edit
#RequestMapping can be added to the controller level as you know, so you should be able to do
#Controller
#RequestMapping("/controller/{companyId}")
as the base url, if that's a better option.
I was able to meet the requirement by making usage of a customized RequestCondition. By defining your own annotation that can be placed at the type and method level of a controller. Extending the RequestMappingHandlerMapping by your own implementation and overriding the getCustomTypeCondition() and getCustomMethodCondition() methods translates a controller annotation into your own RequestCondition.
When a request comes in, the custom RequestCondition will be evaluated and the annotated controller(method) will then be called to serve the request. However this has the downside, that one needs to remove a servlet-context.xml file and switch to the WebMvcConfigurationSupport class instead in order to be able to use your customized RequestMappingHandlerMapping class.
This question was also discussed here.
Edit:
A pretty good example using this can be found here.
I want to make the Request Mappings in my Spring application dynamic. So that my url can not be understandable. And I can show anything meaningless to the user and still mapping purpose will be resolved.
For that I am storing the dynamic part of the URL in properties file. And want to use that in the #RequestMapping annotation. And the same thing will be done on the client side in JSP. I will read the value from the property file and then create the href.
I am using #Value annotation to read the property file values.
There is one class that holds all such values in final static variables.
public class UrlMappingAbstraction {
public static final #Value("#{urlAbstractionProperties['url.message']?:'message'}") String MESSAGE = "";
}
And I am extending this class in my controller and using the static final field in the #RequestMapping annotation like below.
#RequestMapping(value="/"+MESSAGE+"/{id}", method=RequestMethod.GET)
And in jsp also I am reading the value from property file using <spring:message/> and generating the url in href.
The problem is jsp able to create the correct url based on the property file value but in the #RequestMapping annotation my value is not getting replaced.
Can anybody tell me the exact problem? I know that we can not change the value of static final variable after its initialized. Then what's the use of #Value annotation.
If this can be done another way then you can also show me it.
Thanks in advance.
Annotations are static by their nature, therefore you cannot do it this way.
#Value cannot be used on static fields, but it doesn't matter here - the real problem is that there is no way to use values other than compile time constants as attributes of annotations.
You can use one of the following alternatives:
Add a URL rewrite filter (such as this or this) and configure it to perform the necessary conversion.
This approach looks more elegant due to clear separation of responsibilities - controllers are responsible for doing their jobs, rewrite filter is responsible for obfuscation of URLs.
Intercept creation of controller mappings by overriding RequestMappingHandlerMapping. getMappingForMethod() and change their URL patterns at this step (not tested)
I will augment #axtavt's suggestions by saying you should just do it in reverse. Do you really need to make the message URL runtime configurable?
If you don't than just make a static variable just like you have it but with out the #Value:
public final class UrlMapping {
public static final String MESSAGE = "message";
}
Then in your JSP refer to UrlMapping.MESSAGE instead of the properties file.
Although its not as flexible its far simpler and IMHO its a bad idea to make endpoint URLs too configurable because inevitably you will hardcode something either in Javascript or in a template. Also changing URLs are bad for SEO.
You can follow this approach
#Value("${name}")
private String name;
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
src - https://www.baeldung.com/spring-inject-static-field