WebService有多种实现方式,这里使用的是axis2
问题:
在本地开发,访问本地的http://localhost:8080/services/ims?wsdl
,正常访问
但是打成jar包,不管是linux还是window启动,都访问不到,报错信息如下
2023-12-28 09:56:20.749 [http-nio-8092-exec-1] WARN o.a.axiom.util.stax.dialect.StAXDialectDetector[214] - Unable to determine dialect of the StAX implementation at jar:file:/opt/testWebservice.jar!/BOOT-INF/lib/woodstox-core-6.4.0.jar!/
2023-12-28 09:56:21.110 [http-nio-8092-exec-1] ERROR o.apache.axis2.deployment.WarBasedAxisConfigurator[254] - org.apache.axis2.deployment.DeploymentException: The system cannot locate the specified repository location: file:/opt/testWebservice.jar!/BOOT-INF/classes!/WEB-INF: loading repository from classpath
org.apache.axis2.deployment.DeploymentException: The system cannot locate the specified repository location: file:/opt/testWebservice.jar!/BOOT-INF/classes!/WEB-INF
at org.apache.axis2.deployment.DeploymentEngine.loadRepository(DeploymentEngine.java:146)
at org.apache.axis2.deployment.WarBasedAxisConfigurator.getAxisConfiguration(WarBasedAxisConfigurator.java:205)
at org.apache.axis2.context.ConfigurationContextFactory.createConfigurationContext(ConfigurationContextFactory.java:64)
at org.apache.axis2.transport.http.AxisServlet.initConfigContext(AxisServlet.java:622)
at org.apache.axis2.transport.http.AxisServlet.init(AxisServlet.java:471)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1106)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:763)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:115)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1790)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
2023-12-28 09:56:21.160 [http-nio-8092-exec-1] INFO org.apache.axis2.transport.http.AxisServlet[115] - java.lang.NullPointerException
2023-12-28 09:56:21.161 [http-nio-8092-exec-1] ERROR o.a.c.c.C.[Tomcat].[localhost].[/].[axisServlet][175] - Allocate exception for servlet [axisServlet]
java.lang.NullPointerException: null
at org.apache.axis2.deployment.DeploymentEngine.loadServices(DeploymentEngine.java:136)
at org.apache.axis2.deployment.WarBasedAxisConfigurator.loadServices(WarBasedAxisConfigurator.java:275)
at org.apache.axis2.context.ConfigurationContextFactory.createConfigurationContext(ConfigurationContextFactory.java:95)
at org.apache.axis2.transport.http.AxisServlet.initConfigContext(AxisServlet.java:622)
at org.apache.axis2.transport.http.AxisServlet.init(AxisServlet.java:471)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1106)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:763)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:115)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1790)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
原因
axis2默认加载的是项目中的WEB-INF/services/conf/META-INF/services.xml,打包以后默认加载的就是jar中的WEB-INF/services/conf/META-INF/services.xml,但是打包后,又不能读取到services.xml,所以报错了
解决
通过IO流,将services.xml保存到本地,然后指定要加载的路径为本地的这个services.xml
import com.tmkj.tcp.FileCopyUtils;
import org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder;
import org.apache.axis2.transport.http.AxisServlet;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
@Configuration
public class AxisWebserviceConfig {
private final static Logger log = LoggerFactory.getLogger(AxisWebserviceConfig.class);
/*@Bean
public ServletRegistrationBean<AxisServlet> axisServlet() throws Exception {
ServletRegistrationBean<AxisServlet> registrationBean = new ServletRegistrationBean<>();
registrationBean.setServlet(new AxisServlet());
//将 AxisServlet 映射到 /services/* 的URL路径上,所有请求路径以 /services/* 开头的请求将由 AxisServlet 处理
registrationBean.addUrlMappings("/services/*");
// InputStream 对象用于从类路径中读取 services.xml 文件
InputStream in= ClassUtils.getDefaultClassLoader().getResourceAsStream("WEB-INF/services/conf/META-INF/services.xml");
//获取应用程序的当前工作目录,就是当前项目或者jar所在的目录
String root = System.getProperty("user.dir");
//设置本地存储的services.xml的路径
String path=root+"/WEB-INF/services/conf/META-INF/services.xml";
//将前面InputStream的流文件保存到本地指定的路径
FileUtils.copyInputStreamToFile(in,new File(path));
log.info("xml配置文件path={}","{"+root+"/WEB-INF"+"}");
//向 AxisServlet 添加一个初始化参数。初始化参数的名称是 axis2.repository.path ,它的值是 services.xml 文件的路径,这个 root+"/WEB-INF" 已经是我们指定的本地的services.xml路径了,如果不指定,默认加载的就是项目中的WEB-INF/services/conf/META-INF/services.xml,打包以后默认加载的就是jar中的WEB-INF/services/conf/META-INF/services.xml
registrationBean.addInitParameter("axis2.repository.path", root+"/WEB-INF");
//设置 AxisServlet 的加载顺序。加载顺序为1,应用程序启动时将加载 AxisServlet
registrationBean.setLoadOnStartup(1);
return registrationBean;
}*/
@Bean
public ServletRegistrationBean<AxisServlet> axisServlet(){
ServletRegistrationBean<AxisServlet> registrationBean = new ServletRegistrationBean<>();
registrationBean.setServlet(new AxisServlet());
//将 AxisServlet 映射到 /services/* 的URL路径上,所有请求路径以 /services/* 开头的请求将由 AxisServlet 处理
registrationBean.addUrlMappings("/services/*");
/**
* 在项目中:获取当前程序编译后截止/WEB-INF路径,这个WEB-INF在resources目录下,最后结果就是E:/test/target/classes/WEB-INF
* 在jar包中:结果是:file:/opt/yunwang/evn.jar!/BOOT-INF/lib/woodstox-core-6.4.0.jar!/
*/
String path = this.getClass().getResource("/WEB-INF").getPath().toString();
//在jar中的话,把file:截取掉
if(path.toLowerCase().startsWith("file:")){
path = path.substring(5);
}
//如果是jar中,路径中会有!
if(path.indexOf("!") != -1){
try{
//复制classpath下的文件到jar包的同级目录下
FileCopyUtils.copy("WEB-INF/services/conf/META-INF/services.xml");
}catch (Exception e){
e.printStackTrace();
}
path = path.substring(0, path.lastIndexOf("/", path.indexOf("!"))) + "/WEB-INF";
}
log.info("xml配置文件path={}","{"+path+"}");
//向 AxisServlet 添加一个初始化参数。初始化参数的名称是 axis2.repository.path ,它的值是 services.xml 文件的路径,这个 root+"/WEB-INF" 已经是我们指定的本地的services.xml路径了,如果不指定,默认加载的就是项目中的WEB-INF/services/conf/META-INF/services.xml,打包以后默认加载的就是jar中的WEB-INF/services/conf/META-INF/services.xml
registrationBean.addInitParameter("axis2.repository.path", path);
registrationBean.setLoadOnStartup(1);
return registrationBean;
}
/* @Bean
public ApplicationContextHolder getApplicationContextHolder(){
return new ApplicationContextHolder();
}*/
}
以上两个axisServlet
方法,都是一样的,将jar中的文件通过流放在本地,放开一个就行,第一个直接用,第二个是用了一个工具类,以下是工具类
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 将jar内的文件复制到jar包外的同级目录下
*/
public class FileCopyUtils {
private static final Logger log = LoggerFactory.getLogger(FileCopyUtils.class);
private static InputStream getResource(String location) throws IOException {
InputStream in = null;
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
in = resolver.getResource(location).getInputStream();
byte[] byteArray = IOUtils.toByteArray(in);
return new ByteArrayInputStream(byteArray);
} catch (Exception e) {
e.printStackTrace();
log.error("getResource is error: {}", e);
return null;
} finally {
if (in != null) {
in.close();
}
}
}
/**
* 获取项目所在文件夹的绝对路径
*
* @return
*/
private static String getCurrentDirPath() {
URL url = FileCopyUtils.class.getProtectionDomain().getCodeSource().getLocation();
String path = url.getPath();
if (path.startsWith("file:")) {
path = path.replace("file:", "");
}
if (path.contains(".jar!/")) {
path = path.substring(0, path.indexOf(".jar!/") + 4);
}
File file = new File(path);
path = file.getParentFile().getAbsolutePath();
return path;
}
private static Path getDistFile(String path) throws IOException {
String currentRealPath = getCurrentDirPath();
Path dist = Paths.get(currentRealPath + File.separator + path);
Path parent = dist.getParent();
if (parent != null) {
Files.createDirectories(parent);
}
Files.deleteIfExists(dist);
return dist;
}
/**
* 复制classpath下的文件到jar包的同级目录下
*
* @param location 相对路径文件,例如kafka/kafka_client_jaas.conf
* @return
* @throws IOException
*/
public static String copy(String location) throws IOException {
InputStream in = getResource("classpath:" + location);
Path dist = getDistFile(location);
Files.copy(in, dist);
in.close();
return dist.toAbsolutePath().toString();
}
}