The docs state that if I'm not within a servlet calling thread, but still want to make use of UriComponentsBuilder (eg in a batch import), I could use ServletUriComponentsBuilder.fromCurrentContextPath().
#see https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-uri-building
I tried as follows from the docs:
public String createUrl() {
UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en");
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
return uri.toString();
}
For testing a non-servlet call:
#PostConstruct
public void init() {
builder.createUrl();
}
But always getting the exception:
Caused by: java.lang.IllegalStateException: Could not find current request via RequestContextHolder
at org.springframework.util.Assert.state(Assert.java:392) ~[spring-core-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.web.servlet.support.ServletUriComponentsBuilder.getCurrentRequest(ServletUriComponentsBuilder.java:190) ~[spring-webmvc-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.web.servlet.support.ServletUriComponentsBuilder.fromCurrentContextPath(ServletUriComponentsBuilder.java:158) ~[spring-webmvc-4.3.4.RELEASE.jar:4.3.4.RELEASE]
So what might be wrong here?
The documentation you mentioned clearly stated that the static methods are for use in a Servlet environment:
In a Servlet environment the ServletUriComponentsBuilder sub-class
provides static factory methods [...]
So if you're not in said Servlet environment, you need to use plain UriComponentsBuilder:
UriComponentsBuilder.newInstance().scheme("http").host("example.com")
Which would fit into your code as
public String createUrl() {
UriComponentsBuilder base = UriComponentsBuilder.newInstance().scheme("http").host("example.com").path("/en");
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);
URI uri = uriComponents.encode().toUri();
return uri.toString();
}
The reason behind this is that in a servlet environment you can get access to scheme and host and context path by querying the Servlet / ServletContext and so on. Running outside of a webapp, this information (scheme, host, context path) need to come from someplace else.
Related
I have multiple links in my HTML, which are referring to URI in Controller Class,
How can I get this URI in some variable which can be used further, at last, I want to store these URI in DB.
HTML Code :
<td>Win Report</td>
<td>Win Report</td>
Spring Controller Class :
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport() {
return "win_report";
}
#RequestMapping(value = "/ui/report/niw", method = RequestMethod.GET)
public String niwReport() {
return "niw_report";
}
You can use the below solution to retrieve the page Url as well as avoid using repetitive method calls.
You can use a Spring Boot HandlerInterceptor, here's a brief description of the same :
Handler interceptors are used when you want to apply specific
functionality to certain or all requests.
Handler Interceptors should implement the interface HandlerInterceptor. HandlerInterceptor can be used to avoid repetitive handler code.
We can use HandlerInterceptor for different purposes like authorization checks, locale checks, logging, creating common application parameters etc.
HandlerInterceptor works similar to the servlet filter. But in some cases filters are more powerful than HandlerInterceptor.
In Spring-MVC the HandlerInterceptor is configured in spring application context xml file or by Java configuration.
HandlerInterceptor has three methods.
preHandle( ) : It is executed before actual handler is executed.
postHandle( ) : It is executed after handler is executed.
afterCompletion( ) : It is executed after the complete request is finished.
For more details, you can use an example from the below link
https://www.tuturself.com/posts/view?menuId=3&postId=1071
You can get the entire sample project which can help you with the setup at
https://github.com/ninja-panda
To get the request url you can do the following:
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport(HttpServletRequest request){
String request = request.getRequestURI();
// do somehting here
return "win_report"
}
Spring will automatically inject the HttpServletRequest.
Update:
If your want get the urls for all of your methods in your controller, you can go with RequestMappingHandlerMapping:
private final RequestMappingHandlerMapping handlerMapping;
#Autowired
public YourController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
With handlerMapping.getHandlerMethods(), you can access all mappings decleared in your controller. With reflection and getMappingAnnotation, you can then read the value of each RequestMapping annotation.
You can try the getServletPath() like following:
#RequestMapping(value = "/ui/report/win", method = RequestMethod.GET)
public String winReport(HttpServletRequest request){
String mapping = request.getServletPath();
// do somehting here
System.out.println(mapping); // Will print /ui/report/win
return "win_report"
}
I need access to the ServletContext to use the getRealPath() method on some files that are in my WEB-INF directory. However, the class I need to do this work in is a non-CDI class that is used for some backend processing based on a request made earlier from JAX-RS. How can I get the ServletContext outside of the lifecycle of the JAX-RS request?
I'm using Wildfly 10, if that changes the way I would go about this
The trick is to load a servlet at the startup of the Java EE application, see #WebServlet annotation. The Servlet.init() method is invoked upon startup of the container, which we will leverage to work with ServletContext, in this case calling getRealPath() and storing returned value into static variable. You may access the value from the rest of your app by calling RealPathServlet.getRealPath().
#WebServlet(value="/real-path", loadOnStartup=1)
public class RealPathServlet extends HttpServlet {
private static String realPath;
public void init(ServletConfig config) throws ServletException {
super.init(config);
realPath = config.getServletContext().getRealPath("yolo");
Logger.getLogger(ContextPathServlet.class.getName()).info("Real path is " + realPath);
}
public static getRealPath() {
return realPath;
}
...
}
Help! I've been trying for hours, googling anything I could think of. I have a problem, that I would like to show my static content instead of my application on my site.
I modified a simple hello-world application:
public static void main(String[] args) throws Exception {
Class.forName("org.sqlite.JDBC");
new HelloWorldApplication().run(args);
}
#Override
public String getName() {
return "hello-world";
}
#Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle("/assets/*", "/"));
}
#Override
public void run(HelloWorldConfiguration configuration, Environment environment) {
final HelloWorldResource resource = new HelloWorldResource(
configuration.getTemplate(),
configuration.getDefaultName()
);
final AddResource addResource = new AddResource();
final DeleteResource deleteResource = new DeleteResource();
final TemplateHealthCheck healthCheck = new TemplateHealthCheck(configuration.getTemplate());
environment.healthChecks().register("template", healthCheck);
environment.jersey().register(resource);
environment.jersey().register(addResource);
environment.jersey().register(deleteResource);
}
Here's my hello-world.yml:
server:
type: simple
applicationContextPath: /application/hello-world
template: Hello, %s!
defaultName: Stranger
I applied everything, what the DropWizard docs (http://dropwizard.readthedocs.org/en/latest/manual/core.html#serving-assets) said. But I just cannot manage to reach the index.html
I have not seen an actual example that proves that the documented way actually works.
And when looking in the Dropwizard source, I conclude that this is in fact not possible: the Jetty application context is set by the configuration parameter applicationContextPath in SimpleServerFactory:103:
environment.getApplicationContext().setContextPath(applicationContextPath);
And after that, the AssetBundles are registered into this applicationContext upon run() (AssetBundle:109):
environment.servlets().addServlet(assetsName, createServlet()).addMapping(uriPath + '*');
So, assetbundles are always served within the applicationContextPath that is set in the application's YAML file, so serving them outside this applicationContextPath is not possible (despite the docs saying so)
A better way to get this working, is to configure the application to use the / path:
applicationContextPath: /
And then, in your application's code, in the bootstrap() and run() methods, explicitly override the path for Jersey resources and add AssetBundles to your liking:
bootstrap.addBundle(new AssetsBundle("/static", "/"));
environment.jersey().setUrlPattern("/application/*");
I got it working by using the default constructor for the AssetsBundle() class.
With the default constructor your resources will gets looked up in a directory on the java classpath e.g.
/src/main/resources/assets/
and your have to name your applicationContextPath only /application
Point your browser to the folling location for static content
localhost:8080/application/assets/index.htm
For Dropwizard 0.8.0 and newer this is achieved from this configuration:
applicationContextPath: /
rootPath: /application
Where applicationContextPath is Jetty's Context path, and rootPath is Jersey's.
As Geert mentioned, the asset bundle needs to be served from within the applicationContextPath. However, if you add the AssetsBundle in the bootstrap method, and set the contextPath from the run method, the AssetServlet gets added after the contextPath is set.
My fix is to avoid using the AssetsBundle and add the AssetsServlet directly in the run method (after contextPath is set):
environment.getApplicationContext().setContextPath("/");
environment.servlets().addServlet("assets", new AssetServlet("/assets", "/", "index.html", StandardCharsets.UTF_8)).addMapping("/*");
I need application context path in controller, I tried the below code its throwing NULLPOINTER EXCEPTION.
HttpServletRequest request;
String Path = request.getContextPath();
Please help me
Thanks
Variable request is declared, but is not
initialized. No wonder you get a NullPointerException.
Look at documentation to access different request related data.
After you read that, and are sure you want to tie your code to native Servlet API, try this:
#Controller
class MyController {
#RequestMapping
public void handleMe(HttpServletRequest request) {
String path = request.getContextPath();
}
}
I'd like to find the absolute URL of the webapp in Spring, from the Controller. I'm aware of JSTL c:url, but I need this info from inside the Controller.
#Controller
public class AuthorizeController {
#Autowired
private Authorizer auth;
#RequestMapping("/auth")
public String sendToAuthorization() {
String baseUrl = "http://localhost:8080/tasks/";
return "redirect:" + auth.getAuthorizationUrl(baseUrl);
}
}
As you can see the baseUrl is hardcoded, and I could provide it to the Authorizer class via Spring configuration, but I am sure that it's possible to get this information from Spring within the Controller. I tried to google "spring mvc url" and could not find a way to solve this problem.
I think that getting absolute url is only possible while processing the request as your server may have many IP addresses and domain names.
#RequestMapping("/auth")
public String sendToAuthorization(HttpServletRequest request) {
String baseUrl = String.format("%s://%s:%d/tasks/",request.getScheme(), request.getServerName(), request.getServerPort());
return "redirect:" + auth.getAuthorizationUrl(baseUrl);
}
As for the servlet, it may also have several mappings in web.xml.
similar question
P.S. Anyway, url parsing in runtime does not look like a good idea to me.
Very late to this answer, but a variant to Boris's answer, if you don't want to push servlet objects into method signatures, is to use RequestContextHolder from a utility class/method. This would also give the ability to abstract fallback logic (e.g., pulling from a property file). Cheesy example:
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if(null != requestAttributes && requestAttributes instanceof ServletRequestAttributes) {
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// build URL from request
}
else {
// fallback logic if request won't work...
}
This presumes you have org.springframework.web.context.request.RequestContextListener registered as a listener in web.xml