我的 springboot jar 项目,采用了 thin 模式的打包方式,直接在 IDEA 中运行没有问题,但是打包为 jar 后在本地运行就报错:
Invalid value 'com.cc.visitor.config.KaptchaTextCreator' for config parameter 'kaptcha.textproducer.impl'.] with root cause
java.lang.ClassNotFoundException: com.cc.visitor.config.KaptchaTextCreator
下面介绍源码中我认为相关的配置,请帮忙排查为什么会没有找到类 KaptchaTextCreator
- 制作了配置类
SystemConfig
,源码如下
@Configuration
public class SystemConfig {
/**
* 2024年10月10日 15:11:43 依赖 com.github.penggle.kaptcha
* 的验证码工具配置
* @return
*/
@Bean("kaptcha")
public DefaultKaptcha getDefaultKaptcha(){
com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();
Properties properties = new Properties();
properties.put("kaptcha.border", "no");
properties.put("kaptcha.textproducer.font.color", "red");
properties.put("kaptcha.image.width", "170");
properties.put("kaptcha.image.height", "65");
properties.put("kaptcha.textproducer.font.size", "45");
properties.put("kaptcha.session.key", "verifyCode");
properties.put("kaptcha.textproducer.char.space", "6");
properties.put("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.WaterRipple");
// properties.put("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
properties.put("kaptcha.background.clear.from", "yellow");
properties.put("kaptcha.background.clear.to", "green");
properties.put("kaptcha.textproducer.char.length", "4");
properties.put("kaptcha.textproducer.impl", "com.cc.visitor.config.KaptchaTextCreator");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
- 在类
SystemConfig
的同目录下有类KaptchaTextCreator
,源码如下
public class KaptchaTextCreator extends DefaultTextCreator {
private static final String[] NUMBER= "0,1,2,3,4,5,6,7,8,9,10".split(",");
@Override
public String getText() {
Integer result = 0;//结果
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder chinese = new StringBuilder();
int randomop = (int) random.nextInt(4);
//判断结果生成加减乘除
switch (randomop){
case 0 :
result = x * y;
chinese.append(NUMBER[x]);
chinese.append("*");
chinese.append(NUMBER[y]);
break;
case 1 :
if (x == 0 && y % x == 0) {
result = y / x;
chinese.append(NUMBER[y]);
chinese.append("/");
chinese.append(NUMBER[x]);
} else {
result = x + y;
chinese.append(NUMBER[x]);
chinese.append("+");
chinese.append(NUMBER[y]);
}
break;
case 2 :
if (x >= y) {
result = x - y;
chinese.append(NUMBER[x]);
chinese.append("-");
chinese.append(NUMBER[y]);
} else {
result = y - x;
chinese.append(NUMBER[y]);
chinese.append("-");
chinese.append(NUMBER[x]);
}
break;
default:
result = x + y;
chinese.append(NUMBER[x]);
chinese.append("+");
chinese.append(NUMBER[y]);
}
//拼接结果返回
chinese.append("=?" + result);
//chinese.append("=?");
return chinese.toString();
}
}
- 项目
pom.xml
的完整源码如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cc</groupId>
<artifactId>visitor</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>visitor</name>
<description>visitor</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
<com.alibaba.druid.version>1.2.16</com.alibaba.druid.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!-- <version>2.2.2</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-devtools</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- <optional>true</optional>-->
<!-- </dependency>-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 下面是手动添加的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${com.alibaba.druid.version}</version>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>com.cc</groupId>
<artifactId>cc-alltype</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/cc-alltype.jar</systemPath>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 图形验证码 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>visitor.new</finalName>
<plugins>
<!--1、编译出不带lib文件夹的Jar包-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.13</version>
<configuration>
<!--表示编译版本配置有效
<fork>true</fork> -->
<!--引入第三方jar包时,不添加则引入的第三方jar不会被打入jar包中-->
<includeSystemScope>true</includeSystemScope>
<!--排除第三方jar文件-->
<includes>
<include>
<groupId>nothing</groupId>
<artifactId>nothing</artifactId>
</include>
<include>
<groupId>com.cc</groupId>
<artifactId>cc-alltype</artifactId>
</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<!--2、完成对Java代码的编译,可以指定项目源码的jdk版本,编译后的jdk版本,以及编码-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<!--源代码使用的JDK版本-->
<source>${java.version}</source>
<!--需要生成的目标class文件的编译版本-->
<target>${java.version}</target>
<!--字符集编码-->
<encoding>UTF-8</encoding>
<!--用来传递编译器自身不包含但是却支持的参数选项-->
<compilerArguments>
<verbose/>
<!--windwos环境(二选一)-->
<bootclasspath>${env.JAVA_HOME}/jre/lib/rt.jar;${env.JAVA_HOME}/jre/lib/jce.jar</bootclasspath>
<!--Linux环境(二选一)
<bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>-->
</compilerArguments>
</configuration>
</plugin>
<!--3、将所有依赖的jar文件复制到target/lib目录-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!--复制到哪个路径,${project.build.directory}缺醒为target,其他内置参数见下面解释-->
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<!--4、指定启动类,指定配置文件,将依赖打成外部jar包-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!--是否要把第三方jar加入到类构建路径-->
<addClasspath>true</addClasspath>
<!--外部依赖jar包的最终位置-->
<classpathPrefix>lib/</classpathPrefix>
<!--项目启动类-->
<mainClass>com.cc.visitor.VisitorApplication</mainClass>
</manifest>
</archive>
<!--资源文件不打进jar包中,做到配置跟项目分离的效果-->
<excludes>
<!--业务jar中过滤application.properties/yml文件,在jar包外控制-->
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
<exclude>*.yml</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 项目中使用了我自己制作的一个工具
jar
,src
的兄弟目录lib
下有文件cc-alltype.jar
- 通过下图的2个步骤编译
jar
包 - 编译后在项目的
target
目录下有文件visitor.new.jar
和lib
目录 - 将文件
visitor.new.jar
和lib
目录拷贝到另外一个用于部署项目的目录下,如下图: - 其中的
start.bat
用于启动项目,代码是:
@echo off
start javaw -jar visitor.jar --spring.config.location="D:/projs/visitor/backend/application.yml" -Xms512m -Xmx512m -Dfile.encoding=UTF-8 -Dloader.path="D:/projs/visitor/backend/lib/"
exit
- 当访问请求验证码的页面时日志文件中出现报错:
ERROR o.a.c.c.C.[.[.[/visitorbe].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [/visitorbe] threw exception [Request processing failed; nested exception is com.google.code.kaptcha.util.ConfigException: Invalid value 'com.cc.visitor.config.KaptchaTextCreator' for config parameter 'kaptcha.textproducer.impl'.] with root cause
java.lang.ClassNotFoundException: com.cc.visitor.config.KaptchaTextCreator
- 我通过 360 压缩工具打开
visitor.jar
后看到在路径visitor.jar\BOOT-INF\classes\com\cc\visitor\config
下有文件KaptchaTextCreator.class
。为什么还会报没有找到这个类呢?
不知是否列举完全了,请帮忙解决,万分感谢!
你的问题可以参考这个排查
java.lang.ClassNotFoundException 全解析与解决方案
类路径配置错误
依赖冲突或缺失
JAR 文件未加载
编译与运行环境不一致
pom.xml
添加以下代码