如何使用JAX-RS对接Odoo REST服务?技术实现咨询
对接Odoo API的JAX-RS实现问题
背景
我正在开发运行于TomEE的Java Web应用,使用JAX-RS、Jakarta Faces、CDI等Jakarta EE技术,基础功能正常。现在需要对接Odoo服务器执行更新操作,Odoo官方文档里的Java示例依赖Apache XML-RPC包,但该包已14年未更新,存在安全漏洞,所以想改用JAX-RS客户端替代。
Odoo官方XML-RPC示例(获取服务器版本)
官方示例代码:
final String url = "myServer"; final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl(); common_config.setServerURL(new URL(String.format("%s/xmlrpc/2/common", url))); client.execute(common_config, "version", emptyList());
预期返回:
{ "server_version": "13.0", "server_version_info": [13, 0, 0, "final", 0], "server_serie": "13.0", "protocol_version": 1, }
我的JAX-RS尝试及错误
我未安装Apache XML-RPC,尝试用JAX-RS实现相同功能,代码如下:
private final static String pathCommon = "/xmlrpc/2/common"; private final static String odooServer = "http://my.server"; Client client = ClientBuilder.newClient(); WebTarget server = client.target(odooServer); WebTarget common = server.path(pathCommon); Invocation.Builder invoker = common.request(MediaType.TEXT_PLAIN); Entity<String> e = Entity.text("version"); Response resp = invoker.post(e);
请求返回格式错误,响应内容:
Response status: 200, Status type:OK, Status family:SUCCESSFUL, Status phrase:OK Length: 783, has entity: true Data : entity as string: <?xml version='1.0'?> <methodResponse> <fault> <value><struct> <member> <name>faultCode</name> <value><int>1</int></value> </member> <member> <name>faultString</name> <value><string>Traceback (most recent call last): File "/opt/odoo/odoo/odoo/addons/base/controllers/rpc.py", line 69, in xmlrpc_2 response = self._xmlrpc(service) File "/opt/odoo/odoo/odoo/addons/base/controllers/rpc.py", line 48, in _xmlrpc params, method = loads(data) File "/usr/local/lib/python3.8/xmlrpc/client.py", line 1017, in loads p.close() File "/usr/local/lib/python3.8/xmlrpc/client.py", line 447, in close parser.Parse(b"", True) # end of data xml.parsers.expat.ExpatError: syntax error: line 1, column 0 </string></value> </member> </struct></value> </fault> </methodResponse>
需求
- Odoo XML-RPC请求格式的文档指引
- JAX-RS是否适合对接Odoo的这类接口
- JAX-RS调用Odoo接口的示例代码
- Odoo是否提供基于JSON的REST接口
解答
1. Odoo XML-RPC请求格式说明
Odoo的/xmlrpc/2/common接口遵循XML-RPC 2.0规范,要求POST请求的主体是符合XML-RPC格式的XML文档,而非纯文本。XML-RPC的请求结构必须包含<methodCall>节点,明确指定方法名和参数数组。
2. JAX-RS是否适合对接
完全适合。JAX-RS客户端可以构造符合要求的XML请求体,处理XML响应,无需依赖老旧的Apache XML-RPC包,能直接利用现有Jakarta EE技术栈完成对接。
3. JAX-RS调用Odoo版本接口的示例
以下是构造正确XML-RPC请求的JAX-RS代码:
private final static String pathCommon = "/xmlrpc/2/common"; private final static String odooServer = "http://my.server"; // 构造符合XML-RPC规范的请求体 String xmlRequest = """ <?xml version="1.0"?> <methodCall> <methodName>version</methodName> <params> </params> </methodCall> """; Client client = ClientBuilder.newClient(); try { WebTarget target = client.target(odooServer).path(pathCommon); Response response = target.request(MediaType.APPLICATION_XML) .post(Entity.xml(xmlRequest)); if (response.getStatus() == Response.Status.OK.getStatusCode()) { String xmlResponse = response.readEntity(String.class); System.out.println(xmlResponse); // 可使用JAXB或手动解析XML转为Java对象 } else { System.err.println("请求失败,状态码:" + response.getStatus()); } } finally { client.close(); }
如果需要调用带参数的方法(比如认证),只需在<params>节点下添加<param>子节点,示例:
<params> <param><value><string>数据库名</string></value></param> <param><value><string>用户名</string></value></param> <param><value><string>密码</string></value></param> </params>
4. Odoo的JSON REST接口
Odoo提供JSON-RPC接口,路径为/jsonrpc,相比XML-RPC更适合Java应用处理。请求需发送JSON格式的POST数据,示例请求体:
{ "jsonrpc": "2.0", "method": "call", "params": { "service": "common", "method": "version", "args": [] }, "id": 1 }
对应的JAX-RS调用示例:
private final static String pathJsonRpc = "/jsonrpc"; private final static String odooServer = "http://my.server"; // 构造JSON-RPC请求体 String jsonRequest = """ { "jsonrpc": "2.0", "method": "call", "params": { "service": "common", "method": "version", "args": [] }, "id": 1 } """; Client client = ClientBuilder.newClient(); try { WebTarget target = client.target(odooServer).path(pathJsonRpc); Response response = target.request(MediaType.APPLICATION_JSON) .post(Entity.json(jsonRequest)); if (response.getStatus() == Response.Status.OK.getStatusCode()) { String jsonResponse = response.readEntity(String.class); System.out.println(jsonResponse); // 可使用Jackson等JSON库直接转为Java对象 } else { System.err.println("请求失败,状态码:" + response.getStatus()); } } finally { client.close(); }
JSON-RPC接口返回格式为JSON,处理成本更低,推荐优先使用。
内容的提问来源于stack exchange,提问作者Scott Nicklous
相关产品推荐
相关产品推荐

