How to display content in Base URL of Jersey Web Application? - java

I want to ask the basic question about Jersey Application.
Is it possible to add and display HTML content in Base URL? If it is possible, how can I implement it?
I use Jersey 2.X Application.
In the usual, I extends the ResourceConfig to implement and set the ApplicationPath as "/api".
Besides, I set the resource Path as "test" in Test class and define testResp() with "GET" request.
I use maven to build service.war and deploy on local tomcat, so I can access http://localhost:8080/service/api/test to get result in browser.
But now, I want to display some HTML content in API Base URL: http://localhost:8080/service/api/
For example, I will put some introduction for this service and
user can access API Base URL to read.
How can I implement it if possible? Thanks a lot!
Following is the some code example.
Jersey Application sample:
#ApplicationPath("/api")
public class WebApplication extends ResourceConfig {
public WebApplication() {
/**
* register resource, load setting, ...etc
*/
}
}
Resource sample:
#Path("test")
public class Test {
#GET
public Response testResp() {
/**
* impliment the action of http://localhost:8080/service/api/test/
*/
}
}

Create a resource class annotated with #Path("/") or #Path("") then create a resource method to handle GET requests producing HTML:
#Path("/")
public class WelcomeResource {
#GET
#Produces(MediaType.TEXT_HTML)
public Response produceHTML() {
String html = "<p>Hello, World!</p>";
return Response.ok(html).build();
}
}
The HTML content will be available at /api.

Related

Spring Boot 2.7.5 + Angular 15 as a single war

I'm working on a full-stack app having spring boot v2.7.5 as the backend and Angular v15 as the front end. I use IntelliJ IDEA IDE for development. Locally, spring boot runs on http://localhost:8080 and angular runs on http://localhost:4200. I use Gradle to build the project a single war file and which would be deployed on an external tomcat server.
Following is the project structure:
I have 3 build.gradle files, 1 for frontend , 1 for backend, and 1 for global. When I run the global build.gradle file, it would call call build.gradle from fronend folder which builds angular project and copies all the build files and put them into backend/src/main/resources/static folder. Next, build.gradle from the backend gets called which would build the final war file to be deployed on the external tomcat server.
The reason I'm putting frontend build files (index.html, some .js files) into backend/src/main/resources/static is the fact that Spring Boot Serves static content from that location. more details .
So the static directory looks like this after adding frontend build files:
When I try to access http://localhost:8080, it loads index.html from the static folder.
So far it is good. When I click the login button, internally it calls the backend API and moves to the next page (home page i.e., http://localhost:8080/fe/appInstances).
Now if I refresh the page, it gives me the following 404 Whitelabel Error Page.
I understand that since this is spring-boot as it is looking for a definition of the http://localhost:8080/fe/appInstances API endpoint in the java code.
To fix this, I have created the following IndexController.java class which should redirect all the frontend rest endpoints to index.html which is present in main/resources/static folder.
IndexController.java
#Controller
public class IndexController {
#GetMapping("/")
public String index() {
return "redirect:/index";
}
#GetMapping("/fe/*")
public String anyFrontEndApi() {
return "index";
}
}
But now, I get the following Whitelabel error page about Circular view path [index]: would dispatch back to the current handler URL [/fe/index] again.
I have tried changing #Controller to #RestController and changing the return type to ModelandView or something like this. But irrespective of all, it is still giving me the Whitelabel Error Page about Circular view path...
#RestController
public class IndexController {
#GetMapping("/")
public String index() {
return "redirect:/index";
}
#GetMapping("/fe/*")
public ModelAndView anyFrontEndApi() {
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
}
Am I missing something here? Can someone please suggest me a fix for this?
PS: #justthink addressed this situation here. But I don't know how to do reverse proxy way.
We had this situation of page refresh for Angular and Springboot and we resolved this by adding the below Configuration class extending WebMvcConfigurerAdapter
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**/*")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
}
So basically, we are telling Springboot that if we have the resource, use the same if not then redirect it to index.html.
Now, to handle the path in Angular, it depends on how you would have written your routes. If the path is available, you show the page, if not, display 404 page.
Hope this helps.
Update 1:
WebMvcConfigurerAdapter is deprecated. If this causes any trouble, then instead of extending the class WebMvcConfigurerAdapter, you can implement WebMvcConfigurer
If you see the whitelabel error says that "this application has no explicit mapping for /error".
That means if no path is matched with the paths that are defined in controller mappings, it forwards the request to "/error" route. So we can override this default behaviour.
Spring provides ErrorController interface to override this functionality
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class CustomErrorController implements ErrorController {
#RequestMapping("/error")
public String handleError() {
return "forward:/";
}
}

How to intercept a request in Jersey using Annotations?

I'm using Jersey to build a REST API with your standard annotation based routing.
My question is, how can I use a "custom annotation" (in this case #InternalOnly) to intercept a request and run code before the request hits the resource and the // DO STUFF block is executed?
#Path("app")
#Produces(MediaType.APPLICATION_JSON)
public final class SomeResource {
#GET
#Path("something")
#InternalOnly
public Response getSomething() {
// DO STUFF
}
}
I would then have another class that would handle the #InternalOnly header...
public final class InternalOnlyHandler implements SomethingProbably {
public void handle(Object someContext) {
// HANDLE INTERNAL ONLY AUTHENTICATION
}
}
My purpose is basically I need certain API resources to be available internally ONLY and others publicly available and the Authentication is slightly different for both so registering a simple ContainerRequestFilter won't do the job.
I can't figure this out -- please help!

Apache CXF wsdl2java: make service return original WSDL file

I am struggling big time offering a web service based on some WSDL file received from a customer. As described in details here, the WSDL file returned when appending a ?wsdl to the service URL like
http://never.mind/SomeService?wsdl
seems to be misinterpreted by SoapUI and this again prevents the customer from using the service!
I was now hoping that someone could help me understand if it is possible to make the get WSDL endpoint return the original WSDL file instead of some Apache CXF digested version?
Update: I just read somewhere that there is a WSDLGetInterceptor taking care of the get WSDL requests - can I maybe override that one?
I chose to override the getDocument method of the WSDLGetUtils class being used by the WSDLGetInterceptor. My version of the utils class MyWSDLGetUtilsis put into action via this interceptor:
public class WsdlGetSoapInterceptor extends AbstractSoapInterceptor {
public WsdlGetSoapInterceptor() {
super(Phase.READ);
addBefore(WSDLGetInterceptor.class.getName());
}
/** {#inheritDoc} */
#Override
public void handleMessage(final SoapMessage message) throws Fault {
message.setContextualProperty(WSDLGetUtils.class.getName(), MyWSDLGetUtils.Instance);
}
}

Spring MVC 1 to 1 mapping of a URL to .HTML without exposing path

I am using Spring 4.1.5 with Boot 1.2 on a webservice that does not serve up any JSPs. I don't want to add a JSP servlet but I want it to serve up a single canary page that shows in a prettier html type format the information that would be provided at the /manage/health endpoint.
I have a file in webapp/canary/canary.html I want to serve this up from the url: www.mywebservice.com:9343/canary, exactly like that, NOT canary.html
I tried doing this:
#Configuration
public class CanaryConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/canary")
.addResourceLocations("/canary/canary.html");
}
}
That doesn't work however.
It is expecting the handler to provide a file name. So in otherwords the location should be something like: /canary/
and the handler would something like: /canary/**
With that, the URL www.mywebservice.com:9343/canary/canary.html would work like a charm.
HOWEVER, I want the URL to resolve www.mywebservice.com:9343/canary to webapp/canary/canary.html without me having to type the html.
This is really easy in a jsp servlet because you can set the suffix ect...
I looked at ResourceResolver but it didn't make sense to me how I would link that into my current configuration.
It looks like what I want:
Provides mechanisms for resolving an incoming request to an actual Resource and for obtaining the public URL path that clients should use when requesting the resource.
See: ResourceResolver Documentation
Any help would be very beneficial.
Also I am very aware that I can put html in the resources/static and several other places that are automatically configured. That always requires the .html to be typed, which is not what I want in this case so that won't work. Thanks!
You can use view controllers to do it. Here is a sample of it. Hope this helps.
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/canary").setViewName("/canary/canary.html");
}
}
Note: if you are using tomcat, you might have to configure jsp servlet to server html files.
Related post here.
For information sake, the selected answer is the same as the following:
#Controller
public class CanaryController {
#RequestMapping(value="/canary", method=RequestMethod.GET)
public String getCanary() {
return "/canary/canary.html";
}
}
The above code will work as long as canary(or whatever file/folder) is in your webapp folder.
When I tried this I was trying to set the suffix to .html in my YAML (.yml) file and it wasn't working to I thought that it needed to return to a servlet if it is not a RestController. I was mistaken.

JAX-RS, GlassFish, Eclipse. A simple web service doesn't work

I am trying to run a simple "Hello World" RESTful web service on my machine. I use Eclipse Kepler and GlassFish 4.0. I am able to deploy the service and I see it on the admin pages of GlassFish but when I try to access to it I get the following error: "HTTP Status 404 - Not Found".
Herein the code of the simple service:
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
#Path("hello")
public class HelloRest {
#SuppressWarnings("unused")
#Context
private UriInfo context;
/**
* Default constructor.
*/
public HelloRest() {
// TODO Auto-generated constructor stub
}
/**
* Retrieves representation of an instance of HelloRest
* #return an instance of String
*/
#GET
#Produces("application/xml")
public String getXml() {
// TODO return proper representation object
return "<greeting>Hello REST</greeting>";
}
/**
* PUT method for updating or creating an instance of HelloRest
* #param content representation for the resource
* #return an HTTP response with content of the updated or created resource.
*/
#PUT
#Consumes("application/xml")
public void putXml(String content) {
}
}
In order to access to the service I try the following URL: http://127.0.0.1:8080/hello-rest/hello, where hello-rest is the name of the Eclipse project and the root path suggested by the admin page of GlassFish.
Your code seems to be ok, so the problem most likely is that you have not defined the base url for your service. You need to tell JAX-RS (Jersey is the implementation in GlassFish) which url pattern it must intercept as your endpoint (base url).
One way of achieving this is using an Application Class which can be added to any package in the project (you could alternatively define the necessary in a web.xml file which I won't cover). The following is the code:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("your-base-url")
public class ApplicationConfig extends Application {
}
You use the #ApplicationPath annotation to define your base url.
You can then access your service at http://127.0.0.1:8080/hello-rest/your-base-url/hello
#GET
#Produces("application/xml")
#path("/getxml")
public String getXml() {
// TODO return proper representation object
return "<greeting>Hello REST</greeting>";
}
Your url should be http://localhost:8080/hello-rest/hello/getxml
You should mention the path at the method level , so the request is redirected to appropriate method.
You can use SOAPUI to test the service. Please make sure you have choose the correct method.
Method as 'GET'
End point as 'hostname:8080'
Resource as 'hello-rest/hello/getxml'
If you face the same issue. Please attach more logs / exception in tomcat console.

Categories

Resources