Configuring Grizzly with a web.xml - jersey

I can start grizzly and deploy Jersey webservices on it with the following lines.
protected HttpServer create() throws Throwable {
ResourceConfig rc = new PackagesResourceConfig("com.resource", "com.provider");
HttpServer server = GrizzlyServerFactory.createHttpServer(uri, rc);
return server;
}
But is there a way to load a web.xml instead of a ResourceConfig?
<web-app>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.resource, com.provider</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

It seems that there is currently no direct way to configure grizzly with a web.xml. However I have used a partial solution that may be a beginning.
web.xml
First to understand the solution, we must understand what is the meaning of using a web.xml. It is basically use for configure your web application (see this answer for a more detail). In this case we are configuring init-params for the servlet.
The (partial) solution
Instead of using the web.xml and instead of using ResouceConfig.class, we can use Grizzly as our servlet and initializing the parameters.
For example
<web-app>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.resource, com.provider</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
would give something like :
protected HttpServer create() throws Throwable {
HashMap<String, String> initParams = new HashMap<>();
//ServerProperties.PROVIDER_PACKAGES is equal to "jersey.config.server.provider.packages"
initParams.put(ServerProperties.PROVIDER_PACKAGES, "com.resource,com.provider");
//Make sure to end the URI with a forward slash
HttpServer server = GrizzlyWebContainerFactory.create("http://localhost:8080/", initParams);
return server;
}
With this, we can therefore put all the init-params that we want to.
However this solution cannot replace a whole web.xml.

Related

Using DispatcherServlet for RestController

I'm currently trying to understand how the Dispatcher Servlet works with the Rest Controller ,but Postman returns 404 on everything I tried thus far.
The rest controller
#RestController
#RequestMapping(value = "/applications")
public class ApplicationController {
private static final Logger logger = LoggerFactory.getLogger(ApplicationController.class);
#Autowired
#Qualifier("ApplDAO")
private ApplDAO applDAO;
#Autowired
ApplicationService objServices;
#RequestMapping(value = "for_user\\{username:\\d+}", method = RequestMethod.GET)
public Application getApp(#PathVariable("username") String username){
Application app = applDAO.getByUsername(username);
return app;
}
}
My web.xml
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring4-servlet.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I tried using url-pattern /* but with no results.
This is the url I was trying to access http://localhost:8080/project/applications/for_user/username:acid
Is there something wrong with the URL I'm using or have I used the dispatcher wrong.
Here is the spring error
No mapping found for HTTP request with URI [/project/applications/for_user/username:acid
Answered by JB Nizet
Why do you use backslashes instead of slashes in your RequestMapping?
Why do you use the regex \d+ if you want to send username:acid (or
acid?) as user name. Just use value = "/for_user/{username}", and use
http://localhost:8080/project/applications/for_user/acid.

springmvc cannot call controller's method

Currently I got a problem when I configure my springmvc web project.
Below is my web.xml
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
And I defined my dispatcher-servlet.xml like this
<context:component-scan base-package="xxx.controller"
<mvc:annotation-driven />
And in package xxx.controller I define a class TestController
#Controller
#RequestMapping(value="/api")
public class TestController {
#RequestMapping(value = "/hello")
#ResponseBody
public String hello(){
System.out.println("comming hello");
return "hello world";
}
}
Now when I start tomcat, and want to access to localhost:8080/testproject/api/hello, The spring informs me
[10:10:58|WARN |(org.springframework.web.servlet.PageNotFound)]=[No mapping found for HTTP request with URI [/testproject/api/hello] in DispatcherServlet with name 'dispatcher']
But if I modify the url-pattern in web.xml to
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
It is ok to access to localhost:8080/testproject/api/hello. I do not know why this happens. I do want to use /api/* rather than /.
Could anyone helps me configure the controller path mapping? Many thanks!
You are telling your application to run in /api context when you define the following:
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
so to access your controller the URL would have to be localhost:8080/api/api/hello
Just get rid of the /api from your dispatcher as you have and then your mapping should automatically default to localhost:8080/api/hello and work.
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Otherwise if you want to run your application in /api context always you have the option of removing #RequestMapping(value="/api") from your controller.
That way it only recognises the mapping on method.

How to make swagger working with jersey2 and JAX-RS on tomcat 7

I am trying to use swagger in order to document my Rest APIs. I use following link to setup with jersey2 and JAX-RS on tomcat
https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-2.X-Project-Setup-1.5
But I could not access either /swagger.json or /api-docs. Its responding with 404.
What am I doing wrong? Is there a workable documentation? Please help....
Probably you can try to better boil down, which part of the documentation is not yet working in your case.
For me, I used Jersey 2.5.1, and swagger-jersey2-jaxrs_2.10 v. 1.3.4.
I went with the solution to initialize Swagger by a bootstrap class which I included in my web.xml.
bootstrap class
public class SwaggerBootstrap extends HttpServlet {
#Override public void init(ServletConfig servletConfig) {
try {
ServletContext sc = servletConfig.getServletContext();
//as of servlet api 2.5
String ctxPath = sc.getContextPath();
String apiversion = "your-api-version";
String hostname = "your-hostname";
ConfigFactory.config().setBasePath("http://"+hostname+":8080"+ctxPath);
ConfigFactory.config().setApiPath("http://"+hostname+":8080"+ctxPath);
ConfigFactory.config().setApiVersion(apiversion);
ConfigFactory.config().setSwaggerVersion(com.wordnik.swagger.core.SwaggerSpec.version());
System.out.println("Swagger:");
System.out.println("api hostname:"+hostname);
System.out.println("context path:"+ctxPath);
System.out.println("api-version:"+apiversion);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Failed to configure swagger");
}
}
web.xml
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.wordnik.swagger.jersey.listing</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>JerseyJaxrsConfig</servlet-name>
<servlet-class>com.wordnik.swagger.jersey.config.JerseyJaxrsConfig</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>SwaggerBootstrap</servlet-name>
<servlet-class>my.package.swagger.SwaggerBootstrap</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
Hope that helps.

cxf and spring MVC : No service was found

I have spring application, in which I use org.apache.cxf for soap and spring MVC for displayng some pages.
My web.xml contains two servlets :CXFServlet and mvc-dispatcher
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/servlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
When I has been used #ResponseBody in my controller everything was fine.
#Controller
#RequestMapping("/hello")
#ResponseBody
public class HelloController {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome() {
return "hello" ;
}
}
but then i was needed to use jsp I have to use the following
#Controller
#RequestMapping("/hello")
public class HelloController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView printWelcome(ModelMap model) {
model.addAttribute("message", "hello");
return new ModelAndView("hello") ;
}
}
and when I request http://localhost:8080/hello I get "No service was found" instead of "hello"
I found that if I delete following from web.xml
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
my controller works fine.
The Servlet container you are using is matching CXFServlet instead of mvc-dispatcher for the URI http://localhost:8080/hello, resulting in your request being sent to CXFServlet, and the error message "No service was found" being returned by CXFServlet. To quote the Servlet 3.0 spec,
Versions of this specification prior to 2.5 made use of these mapping
techniques as a suggestion rather than a requirement, allowing servlet
containers to each have their different schemes for mapping client
requests to servlets.
http://download.oracle.com/otndocs/jcp/servlet-3.0-fr-eval-oth-JSpec/
You will likely need to configure you CXFServlet mapping to something else, e.g.
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
You might want to mention the container (Tomcat, Glassfish, etc.) that you are using, as there could also be a bug preventing this from working correctly.

How can I let spring+cometd support webscoket?

I use chrome, it always return:
WebSocket connection to 'ws://192.168.1.228:9090/achat/cometd' failed: Unexpected response code: 400
After this error, it use long-polling transport, and success to connect to the server.
How can I let WebSocket work? Is it caused by using SpringFramework 3.1? Thanks.
Web.xml
<!-- Filter to support cross domain requests -->
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<!--async-supported>true</async-supported-->
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/cometd/*</url-pattern>
</filter-mapping>
<!-- Cometd Servlet -->
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.annotation.AnnotationCometdServlet</servlet-class>
<!--async-supported>true</async-supported-->
<init-param>
<param-name>timeout</param-name>
<param-value>20000</param-value>
</init-param>
<init-param>
<param-name>interval</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>maxInterval</param-name>
<param-value>10000</param-value>
</init-param>
<init-param>
<param-name>maxLazyTimeout</param-name>
<param-value>5000</param-value>
</init-param>
<init-param>
<param-name>long-polling.multiSessionInterval</param-name>
<param-value>2000</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>100</param-value>
</init-param>
<init-param>
<param-name>transports</param-name>
<param-value>org.cometd.websocket.server.WebSocketTransport</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>
Servlet
#Named
#Singleton
#Service
public class ChatService {
#Inject
private BayeuxServer bayeux;
#Session
private ServerSession serverSession;
#Listener("/chat")
public void processHello(ServerSession remote, ServerMessage.Mutable message)
{
Map<String, Object> input = message.getDataAsMap();
String room = input.get("room").toString();
String content = input.get("content").toString();
Map<String, Object> output = input;
bayeux.getChannel("/room/" + room).publish(remote, output, null);
}
}
Follow the CometD Reference Manual, specifically the section that explains how to integrate CometD with Spring.
There you can find an example that uses Spring's XML configuration to setup WebSocket, and an example of how to configure Spring via annotations.
Your question lacks the Spring configuration file and part of the web.xml file so it is difficult to help you in a more detailed way.
Just remember that if you configure CometD in Spring, then you must remove all the CometD configuration from web.xml. You must have only one place where you configure things: either web.xml or Spring's XML/annotations.

Resources