RestEasy open html/jsp page - rest

There is a RestEasy method, which handles #GET requests. How is it possible to open a jsp/html page from that method?
#GET
#Path("/")
public void getMainPage(){
//...
}

HtmlEasy is a great tool to render jsp files through RestEasy.
#Path("/")
public class Welcome {
#GET #Path("/welcome/{name}")
public View sayHi(#PathParm("name") String name) {
return new View("/welcome.jsp", name);
}
}
See documents for all options.

Using org.jboss.resteasy.resteasy-html version 3.0.6.Final you can directly access the HttpServletRequest and inject your own attributes before directing output to a RESTEasy View.
#GET
#Path("{eventid}")
#Produces("text/html")
public View getEvent(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("eventid") Long eventid){
EventDao eventdao = DaoFactory.getEventDao();
Event event = eventdao.find(eventid);
request.setAttribute("event", event);
return new View("eventView.jsp");
}
This emulates some behavior of the Htmleasy plugin without having to rewire your web.xml.

Related

How to get user info directly at JPA level in rest api

I am using REST api with JPA, and getting the user information in the header section .
For audit purpose need to save the user detail with each request.
How to directly get the user info at JPA level (#Prepersist and #PreUpdate hooks) from rest header.
I don't want to pass the details though service layer
Is there any generic way to do it ?
Note-I am not using spring.
Thanks in advance.
I had the similar problem with spring framework. Following idea may help you.
Create AppContext using ThreadLocal
public class AppContext {
private static final ThreadLocal<User> currentUser = new ThreadLocal<>();
public static void setCurrentUser(String tenant) {
currentUser.set(tenant);
}
public static String getCurrentUser() {
return currentUser.get();
}
public static void clear() {
currentUser.remove();
}
}
Use filter or similar to get user from http header and set to the AppContext
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// Your code to extract user info from header
// Build user object and set to the AppContext
AppContext.setCurrentUser(user);
//doFilter
chain.doFilter(httpRequest, response);
}
Use AppContext on the repository. It should available on request scope.
#PrePersist
public void onPrePersist() {
if(AppContext.getCurrentUser() != null){
this.user = AppContext.getCurrentUser();
}
}
}

Java EE Servlet and REST path clashing

I am trying to write a Java web application that provides both HTML and REST interface. I would like to create a servlet that would provide the HTML interface using JSP, but data should also be accessible via REST.
What I already have is something like this for the REST:
#javax.ws.rs.Path("/api/")
public class RestAPI {
... // Some methods
}
and
#WebServlet("/servlet")
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Howdy at ");
}
}
Now, when I change the #WebServlet("/servlet") annotation to #WebServlet("/"), the servlet stops working probably due to path clash with the REST.
How can I provide REST on specific path and HTML in the root?
Thank you,
Lukas Jendele
This seems to work OK for me. What I did:
In my pom.xml, I have a dependency on org.wildfly.swarm:undertow (for Servlet API) and org.wildfly.swarm:jaxrs (for JAX-RS). And of course the Swarm Maven plugin.
For servlet, I have just this one class:
#WebServlet("/")
public class HelloServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello from servlet");
}
}
For JAX-RS, I have these 2 classes:
#ApplicationPath("/api")
public class RestApplication extends Application {
}
#Path("/")
public class HelloResource {
#GET
public Response get() {
return Response.ok().entity("Hello from API").build();
}
}
To test, I run curl http://localhost:8080/ and curl http://localhost:8080/api. Results are as expected. (Maybe my example is too simple?)

Swagger UI does not list any of the controller/end points though I am able to see the json under v2/api-docs endpoint

I am not able to get my Swagger UI to work with my project. Swagger UI comes up fine but it does not list any of my REST controllers.
I am using SPRING 4.2.6.RELEASE and Swagger 2.5.0 . My rest services are deployed to Tomcat 7.0.54 .
When Tomcat 7.0.54 comes up, it is able to fetch the swagger end points.
I am able to hit the endpoint v2/api-docs that fetches the json messages.
I am also able to hit the swagger-ui but I dont see any controllers listed.
The dropdowns are empty, as below
**The issue I am facing currently is that
I am not able to fetch the /swagger-resources/configuration/ui, when I launch the swagger UI I get 404 (Not Found) errror while the UI is trying to fetch /swagger-resources/configuration/ui . I have setup resource handlers for swagger-resources, but that does not seem to help. Can you please let me know what could be missing?
Should I be seeing resources folder under META-INF in my expanded WAR? Should there be any springfox related files/folder inside META-INF?
**
Maven dependency for Swagger
io.springfox
springfox-swagger2
2.5.0
io.springfox
springfox-swagger-ui
2.5.0
Below is my SwaggerCongifuration
#EnableSwagger2
public class SwaggerConfiguration {
#Bean
public Docket api() {
List<SecurityContext> security = new ArrayList<SecurityContext>();
security.add(securityContext());
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.pathMapping("/").securityContexts(security);
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.forPaths(PathSelectors.regex("/"))
.build();
}
}
Below is my WebConfig.xml
#EnableWebMvc
#Configuration
#Import(SwaggerConfiguration.class)
#ComponentScan("com.bank.direct.services")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> pConverters) {
pConverters.add(RestUtils.getJSONMessageConverter());
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Below is the SecurityCongif.xml
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationService _authenticationService;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder pAuth) throws Exception {
pAuth.userDetailsService(_authenticationService);
}
#Override
protected void configure(HttpSecurity pHttp) throws Exception {
// Enable HTTP caching
pHttp.headers().cacheControl().disable();
// Configure security
pHttp.httpBasic()
// -- Allow only authenticated request
.and()
.authorizeRequests()
.anyRequest().authenticated()
// -- Logout configuration
.and()
.logout()
.logoutUrl("/rest/users/logout/")
.deleteCookies("XSRF-TOKEN")
.logoutSuccessUrl("/static/index.html")
.invalidateHttpSession(true)
// -- CSRF configuration
.and()
.csrf().csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class);
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
Rest Controller class as below
#RestController
#RequestMapping(value = "/vehicles", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class VehicleResource extends Resource {
#Autowired
private IVehicleService _vehicleService;
#RequestMapping(value = "/brands", method = RequestMethod.GET)
public APIResponseEntity getBrands(WebRequest pWebRequest) {
IUser user = getUser(pWebRequest);
BrandCriteria criteria = new BrandCriteria();
criteria.setLanguageCode(user.getLanguageCode());
List<Brand> res = _vehicleService.getBrands(user, criteria);
return newResponseOK(res);
}
#RequestMapping(value = "/brands/{brand_code}", method = RequestMethod.GET)
public APIResponseEntity getBrand(WebRequest pWebRequest, #PathVariable("brand_code") String pBrandCode) {
IUser user = getUser(pWebRequest);
BrandCriteria criteria = new BrandCriteria();
criteria.setLanguageCode(user.getLanguageCode());
criteria.setBrandCode(pBrandCode);
List<Brand> res = _vehicleService.getBrands(user, criteria);
return newResponseOK(res);
}
}
After migrating an older project from XML Spring configuration to Java Spring configuration and updating spring and Swagger versions I struggled with an issue that sounds exactly like this so I thought I'd document my solution here.
I had a number of problems but the main ones that match the OP's scenario were that while /v2/api-docs was accessible and returned JSON, my Controllers clearly weren't being picked up, and when I accessed the Swagger UI at /swagger-ui.html, I was getting a 404 when that page tried to request /swagger-resources/configuration/ui
My Swagger configuration class was:
#Configuration
#EnableSwagger2
public class SwaggerWebConfig {
#Bean
public Docket api() {
...
}
}
The #EnableSwagger2 annotation imports another configuration class Swagger2DocumentationConfiguration, which in turn imports SwaggerCommonConfiguration, which does a component scan for classes in springfox.documentation.swagger.web which finally loads the ApiResourceController, which is where
/swagger-resources/
/swagger-resources/configuration/security and
/swagger-resources/configuration/ui
are served from.
What I had incorrect was that my SwaggerWebConfig class was being loaded by the root application context, when it should belong to the web application context (see ApplicationContext vs WebApplicationContext).
Beans in the web application context can access beans in the root application context, but not the other way around, which explained why Docket bean (incorrectly in the root application context) could not pick up the #Controller beans in the web application context and also explained why despite the ApiResourceController bean being created, its methods were giving 404's when trying to access them (they should be in the web application context)
A few other notes for related issues:
If you can hit v2/api-docs then your Docket bean is working
In a non-spring-boot environment, you need to register two resource handlers yourself as spring boot's auto-configuration would have done this for you as explained in the answers to this question. That should solve 404's for:
/swagger-ui.html (i.e. 404 fetching the actual html swagger-ui.html page)
and the three webjars that swagger-ui.html loads:
/webjars/springfox-swagger-ui/springfox.js
/webjars/springfox-swagger-ui/swagger-ui-bundle.js
/webjars/springfox-swagger-ui/swagger-ui-standalone-preset.js
If you are getting an access denied rather than a 404 not found, then as shown in this answer, you might need to tell spring security to allow access to:
/webjars/**
/swagger-ui.html
/v2/api-docs
/swagger-resources/**
You need to point the the generated Swagger Definition in Swagger UI. i.e in place of http://example.com/api give your swagger definition path something like http://localhost:8080/RestResource/api/swagger.json
This article might help you more

How to get the url of called method resteasy

I making one Rest Service with Restaeasy (java) that have to return the same URL that was called but with one new string
Example Call service:
Post => mybase/myservice/somewrite with some JSON
| Reponse => mybase/myservice/somewrite/123456
So i want to make the mybase/myservice/somewrite url with one generic logic, because if i put String returnURL="mybase/myservice/somewrite"; and i change for example the name of mybase the reponse will not be good
I want somthing like this
someLogicService(JSON);
id=getId();
URL=getContextCallURL();
return URL+\/+id;
But i dont know if this is possible to do it, and less how to do it
You could also inject an instance of type UriInfo using the annotation Context within your resource, as described below:
#Context
private UriInfo uriInfo;
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
public Response makeContact(Contact contact) {
String requestUri = uriInfo.getRequestUri();
(...)
}
Hope it helps you,
Thierry
I found the answer to my problem, i put inject with #context the httpRequest to my function and call absolutPath :
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
public Response makeContact(Contact contact, #Context HttpRequest request) {
return Response.ok().header("location", request.getUri().getAbsolutePath().getPath() + contactService.makeContact(contactJSON)).build();
}

Dynamic Query Param

I have requirement where Query Param name is not fixed. i.e.
/Test/Add?a=b,c&a1=b1,c1
/Test/Add?d=e,f&c1=d1,f1
I have read in some article saying use #Context URI, HttpServlerRequest.
Can you please guide me how to implement this in Jersey?
You could add the UriInfo to your class like this:
public class Example {
#Context
UriInfo uriInfo;
#GET
#Path("/")
public void get() {
System.out.println(uriInfo.getPathParameters());
}
}