Skip to content

Commit d8a2764

Browse files
committed
添加 solonx-web-webservices-jakarta 模块
1 parent c03f882 commit d8a2764

File tree

12 files changed

+440
-0
lines changed

12 files changed

+440
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices;
17+
18+
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
19+
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
20+
21+
22+
/**
23+
* WS 助手
24+
*
25+
* @author noear
26+
* @since 1.0
27+
*/
28+
public class WebServiceHelper {
29+
/**
30+
* 发布 Web 服务
31+
*/
32+
public static void publishWebService(String wsAddress, Object wsImplementInstance) {
33+
publishWebService(wsAddress, wsImplementInstance, null);
34+
}
35+
36+
/**
37+
* 发布 Web 服务
38+
*/
39+
public static void publishWebService(String wsAddress, Object wsImplementInstance, Class<?> wsInterfaceClass) {
40+
if (wsInterfaceClass == null) {
41+
wsInterfaceClass = wsImplementInstance.getClass();
42+
}
43+
44+
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
45+
factory.setAddress(wsAddress); // 地址
46+
factory.setServiceClass(wsInterfaceClass); // 接口
47+
factory.setServiceBean(wsImplementInstance); // 实现
48+
factory.create();
49+
}
50+
51+
/**
52+
* 创建 Web 服务客户端
53+
*/
54+
public static <T> T createWebClient(String wsAddress, Class<? extends T> interfaceClass) {
55+
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
56+
factory.setAddress(wsAddress); // 地址
57+
factory.setServiceClass(interfaceClass); // 接口
58+
return factory.create(interfaceClass);
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices;
17+
18+
import java.lang.annotation.*;
19+
20+
/**
21+
* WS 服务引用
22+
*
23+
* @author noear
24+
* @since 1.0
25+
*/
26+
@Target({ElementType.FIELD})
27+
@Retention(RetentionPolicy.RUNTIME)
28+
@Documented
29+
public @interface WebServiceReference {
30+
/**
31+
* 服务地址
32+
* */
33+
String value();
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices.integration;
17+
18+
import jakarta.jws.WebService;
19+
import org.noear.solon.core.BeanBuilder;
20+
import org.noear.solon.core.BeanWrap;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
/**
26+
* @author noear
27+
* @since 1.0
28+
*/
29+
public class WebServiceBeanBuilder implements BeanBuilder<WebService> {
30+
private List<BeanWrap> wsBeanWarps = new ArrayList<>();
31+
32+
public List<BeanWrap> getWsBeanWarps() {
33+
return wsBeanWarps;
34+
}
35+
36+
@Override
37+
public void doBuild(Class<?> clz, BeanWrap bw, WebService anno) throws Throwable {
38+
if (clz.isInterface() == false) {
39+
wsBeanWarps.add(bw);
40+
}
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices.integration;
17+
18+
import org.noear.solon.Solon;
19+
import org.noear.solon.Utils;
20+
21+
import jakarta.servlet.ServletContainerInitializer;
22+
import jakarta.servlet.ServletContext;
23+
import jakarta.servlet.ServletException;
24+
import jakarta.servlet.ServletRegistration;
25+
import java.util.Set;
26+
27+
/**
28+
* @author noear
29+
* @since 1.0
30+
*/
31+
public class WebServiceContainerInitializerImpl implements ServletContainerInitializer {
32+
@Override
33+
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
34+
//@WebServlet(name = "ws", urlPatterns = "/ws/*", loadOnStartup = 0)
35+
String path = Solon.cfg().get("server.webservices.path");
36+
37+
if (Utils.isEmpty(path)) {
38+
path = "/ws/*";
39+
} else {
40+
if (path.startsWith("/") == false) {
41+
path = "/" + path;
42+
}
43+
44+
if (path.endsWith("/")) {
45+
path = path + "*";
46+
} else {
47+
path = path + "/*";
48+
}
49+
}
50+
51+
ServletRegistration.Dynamic registration = servletContext.addServlet("WebServiceServlet", WebServiceServlet.class);
52+
if (registration != null) {
53+
registration.setLoadOnStartup(0);
54+
registration.addMapping(path);
55+
}
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices.integration;
17+
18+
import org.noear.solon.core.AppContext;
19+
import org.noear.solon.core.Plugin;
20+
import org.noear.solon.web.webservices.WebServiceReference;
21+
22+
import jakarta.jws.WebService;
23+
import jakarta.servlet.ServletContainerInitializer;
24+
25+
/**
26+
* @author noear
27+
* @since 1.0
28+
*/
29+
public class WebServicePlugin implements Plugin {
30+
@Override
31+
public void start(AppContext context) throws Throwable {
32+
WebServiceBeanBuilder wsBeanBuilder = new WebServiceBeanBuilder();
33+
34+
//注册 Bean
35+
context.wrapAndPut(ServletContainerInitializer.class, new WebServiceContainerInitializerImpl());
36+
context.wrapAndPut(WebServiceBeanBuilder.class, wsBeanBuilder);
37+
38+
//添加 Anno 处理
39+
context.beanBuilderAdd(WebService.class, wsBeanBuilder);
40+
context.beanInjectorAdd(WebServiceReference.class, new WebServiceReferenceBeanInjector());
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices.integration;
17+
18+
import org.noear.solon.core.BeanInjector;
19+
import org.noear.solon.core.VarHolder;
20+
import org.noear.solon.web.webservices.WebServiceReference;
21+
import org.noear.solon.web.webservices.WebServiceHelper;
22+
23+
import java.util.Map;
24+
import java.util.concurrent.ConcurrentHashMap;
25+
26+
/**
27+
* @author noear
28+
* @since 1.0
29+
*/
30+
public class WebServiceReferenceBeanInjector implements BeanInjector<WebServiceReference> {
31+
private Map<String, Object> cached = new ConcurrentHashMap<>();
32+
33+
@Override
34+
public void doInject(VarHolder varH, WebServiceReference anno) {
35+
if (varH.getType().isInterface()) {
36+
37+
String wsKey = anno.value() + "#" + varH.getType().getTypeName();
38+
Object wsProxy = cached.computeIfAbsent(wsKey, k -> WebServiceHelper.createWebClient(anno.value(), varH.getType()));
39+
40+
varH.setValue(wsProxy);
41+
}
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2017-2025 noear.org and authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.noear.solon.web.webservices.integration;
17+
18+
import org.apache.cxf.Bus;
19+
import org.apache.cxf.BusFactory;
20+
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
21+
import org.noear.solon.Solon;
22+
import org.noear.solon.Utils;
23+
import org.noear.solon.core.BeanWrap;
24+
import org.noear.solon.web.webservices.WebServiceHelper;
25+
26+
import jakarta.jws.WebService;
27+
import jakarta.servlet.ServletConfig;
28+
29+
public class WebServiceServlet extends CXFNonSpringServlet {
30+
@Override
31+
protected void loadBus(ServletConfig sc) {
32+
// 设置 Bus
33+
setBus(sc);
34+
// 发布 Web 服务
35+
publishWebService();
36+
}
37+
38+
private void setBus(ServletConfig sc) {
39+
super.loadBus(sc);
40+
Bus bus = getBus();
41+
BusFactory.setDefaultBus(bus);
42+
}
43+
44+
private void publishWebService() {
45+
// 遍历所有标注了 @WebService 注解的接口
46+
WebServiceBeanBuilder wsBeanBuilder = Solon.context().getBean(WebServiceBeanBuilder.class);
47+
48+
for (BeanWrap bw : wsBeanBuilder.getWsBeanWarps()) {
49+
// 获取 name 属性
50+
WebService anno = bw.clz().getAnnotation(WebService.class);
51+
String name = Utils.annoAlias(anno.name(), anno.serviceName());
52+
// 获取 Web 服务地址
53+
String wsAddress = getAddress(name, bw.clz());
54+
// 获取 Web 服务实现类(找到唯一的实现类)
55+
Class<?> wsImplementClass = bw.clz();
56+
// 获取实现类的实例
57+
Object wsImplementInstance = bw.raw();
58+
// 发布 Web 服务
59+
WebServiceHelper.publishWebService(wsAddress, wsImplementInstance, wsImplementClass);
60+
61+
}
62+
}
63+
64+
private String getAddress(String value, Class<?> wsInterfaceClass) {
65+
String address;
66+
if (Utils.isNotEmpty(value)) {
67+
// 若不为空,则为 value
68+
address = value;
69+
} else {
70+
// 若为空,则为类名
71+
address = wsInterfaceClass.getSimpleName();
72+
}
73+
74+
// 确保最前面只有一个 /
75+
if (!address.startsWith("/")) {
76+
address = "/" + address;
77+
}
78+
79+
address = address.replaceAll("\\/+", "/");
80+
return address;
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
solon.plugin=org.noear.solon.web.webservices.integration.WebServicePlugin
2+
solon.plugin.priority=1
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package demo.client;
2+
3+
4+
import org.noear.solon.web.webservices.WebServiceHelper;
5+
6+
import jakarta.jws.WebMethod;
7+
import jakarta.jws.WebService;
8+
9+
public class ClientTest {
10+
public static void main(String[] args) {
11+
String wsAddress = "http://localhost:8080/ws/HelloService";
12+
HelloService helloService = WebServiceHelper.createWebClient(wsAddress, HelloService.class);
13+
14+
System.out.println("rst::" + helloService.hello("noear"));
15+
}
16+
17+
@WebService(serviceName = "HelloService", targetNamespace = "http://demo.solon.io")
18+
public interface HelloService {
19+
@WebMethod
20+
String hello(String name);
21+
}
22+
}

0 commit comments

Comments
 (0)