301.7. 示例
从 Camel 2.7 开始,在 Spring web 应用程序中使用 Servlet 更容易。详情请查看 Servlet Tomcat 示例。
在这个示例中,我们定义在 http://localhost:8080/camel/services/hello 中公开 HTTP 服务的路由。
首先,您需要通过普通的 Web 容器或 OSGi 服务发布 CamelHttpTransportServlet。使用 Web.xml
文件发布 CamelHttpTransportServlet,如下所示:
<web-app> <servlet> <servlet-name>CamelServlet</servlet-name> <display-name>Camel Http Transport Servlet</display-name> <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CamelServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> </web-app>
然后,您可以按照以下方式定义路由:
from("servlet:hello?matchOnUriPrefix=true").process(new Processor() { public void process(Exchange exchange) throws Exception { String contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class); String path = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class); path = path.substring(path.lastIndexOf("/")); assertEquals("Get a wrong content type", CONTENT_TYPE, contentType); // assert camel http header String charsetEncoding = exchange.getIn().getHeader(Exchange.HTTP_CHARACTER_ENCODING, String.class); assertEquals("Get a wrong charset name from the message heaer", "UTF-8", charsetEncoding); // assert exchange charset assertEquals("Get a wrong charset naem from the exchange property", "UTF-8", exchange.getProperty(Exchange.CHARSET_NAME)); exchange.getOut().setHeader(Exchange.CONTENT_TYPE, contentType + "; charset=UTF-8"); exchange.getOut().setHeader("PATH", path); exchange.getOut().setBody("<b>Hello World</b>"); } });
指定 camel-servlet 端点的相对路径
由于我们将 HTTP 传输与公布的 servlet 绑定,因此我们不知道 servlet 的应用上下文路径,camel-servlet
端点使用相对路径来指定端点的 URL。客户端可以通过 servlet 发布地址访问 camel-servlet
端点: ("http://localhost:8080/camel/services")+ RELATIVE_PATH ("/hello")
301.7.1. 使用 Spring 3.x 时的示例
请参阅 Servlet Tomcat 示例。
301.7.2. 使用 Spring 2.x 时的示例
当在 Camel/Spring 应用程序中使用 Servlet 组件时,通常需要在 Servlet 组件启动后加载 Spring ApplicationContext。这可以通过使用 Spring 的 ContextLoaderServlet
而不是 ContextLoaderListener
来完成。在这种情况下,您需要在 CamelHttpTransportServlet 后启动 ContextLoaderServlet
,如下所示:
<web-app> <servlet> <servlet-name>CamelServlet</servlet-name> <servlet-class> org.apache.camel.component.servlet.CamelHttpTransportServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>SpringApplicationContext</servlet-name> <servlet-class> org.springframework.web.context.ContextLoaderServlet </servlet-class> <load-on-startup>2</load-on-startup> </servlet> <web-app>
301.7.3. 使用 OSGi 时的示例
在 Camel 2.6.0 中,您可以使用类似如下的蓝图发布 CamelHttpTransportServlet 作为 OSGi 服务:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <bean id="camelServlet" class="org.apache.camel.component.servlet.CamelHttpTransportServlet" /> <!-- Enlist it in OSGi service registry. This will cause two things: 1) As the pax web whiteboard extender is running the CamelServlet will be registered with the OSGi HTTP Service 2) It will trigger the HttpRegistry in other bundles so the servlet is made known there too --> <service ref="camelServlet"> <interfaces> <value>javax.servlet.Servlet</value> <value>org.apache.camel.http.common.CamelServlet</value> </interfaces> <service-properties> <entry key="alias" value="/camel/services" /> <entry key="matchOnUriPrefix" value="true" /> <entry key="servlet-name" value="CamelServlet" /> </service-properties> </service> </blueprint>
然后,在您的 Camel 路由中使用这个服务,如下所示:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <reference id="servletref" ext:proxy-method="classes" interface="org.apache.camel.http.common.CamelServlet"> <reference-listener ref="httpRegistry" bind-method="register" unbind-method="unregister" /> </reference> <bean id="httpRegistry" class="org.apache.camel.component.servlet.DefaultHttpRegistry" /> <bean id="servlet" class="org.apache.camel.component.servlet.ServletComponent"> <property name="httpRegistry" ref="httpRegistry" /> </bean> <bean id="servletProcessor" class="org.apache.camel.example.servlet.ServletProcessor" /> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route> <!-- Notice how we can use the servlet scheme which is that reference above --> <from uri="servlet://hello" /> <process ref="servletProcessor" /> </route> </camelContext> </blueprint>
对于 Camel 2.6 之前的版本,您可以使用 Activator
在 OSGi 平台上发布 CamelHttpTransportServlet :
import java.util.Dictionary; import java.util.Hashtable; import org.apache.camel.component.servlet.CamelHttpTransportServlet; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.osgi.context.BundleContextAware; public final class ServletActivator implements BundleActivator, BundleContextAware { private static final Logger LOG = LoggerFactory.getLogger(ServletActivator.class); private static boolean registerService; /** * HttpService reference. */ private ServiceReference<?> httpServiceRef; /** * Called when the OSGi framework starts our bundle */ public void start(BundleContext bc) throws Exception { registerServlet(bc); } /** * Called when the OSGi framework stops our bundle */ public void stop(BundleContext bc) throws Exception { if (httpServiceRef != null) { bc.ungetService(httpServiceRef); httpServiceRef = null; } } protected void registerServlet(BundleContext bundleContext) throws Exception { httpServiceRef = bundleContext.getServiceReference(HttpService.class.getName()); if (httpServiceRef != null && !registerService) { LOG.info("Register the servlet service"); final HttpService httpService = (HttpService)bundleContext.getService(httpServiceRef); if (httpService != null) { // create a default context to share between registrations final HttpContext httpContext = httpService.createDefaultHttpContext(); // register the hello world servlet final Dictionary<String, String> initParams = new Hashtable<String, String>(); initParams.put("matchOnUriPrefix", "false"); initParams.put("servlet-name", "CamelServlet"); httpService.registerServlet("/camel/services", // alias new CamelHttpTransportServlet(), // register servlet initParams, // init params httpContext // http context ); registerService = true; } } } public void setBundleContext(BundleContext bc) { try { registerServlet(bc); } catch (Exception e) { LOG.error("Cannot register the servlet, the reason is " + e); } } }
301.7.4. 使用 Spring-Boot
从 Camel 2.19.0 开始,camel-servlet-starter 库会在 /camel
PROFILE 上下文路径下自动绑定所有剩余的端点。下表总结了 camel-servlet-starter 库中提供的其他配置属性。也可以禁用 Camel servlet 的自动映射。
spring-Boot Property | default | 描述 |
---|---|---|
camel.component.servlet.mapping.enabled |
| 启用 servlet 组件的自动映射到 Spring web 上下文 |
camel.component.servlet.mapping.context-path |
| servlet 组件用于自动映射的上下文路径 |
camel.component.servlet.mapping.servlet-name |
| Camel servlet 的名称 |