项目场景:
项目场景:简单的SSM架构CRM项目,属于一个练习项目,由于视频上使用的较旧的技术,所以在自己做的时候全部替换为新的内容。
开发环境:
1. JAVA:21.0.2
2. Maven:3.9.6
3. Spring:6.1.6
4. 数据库:MariaDB11.0
5. MyBatis:3.5.16
6. IDE:eclipse
问题描述
在编写了Controller方法后(方法接收参数HttpServletRequest),当前端访问Controller时,会报错,报错信息如下:
5月 18, 2024 9:30:42 下午 org.apache.catalina.core.StandardWrapperValve invoke
严重: 在路径为[/crm-core]的上下文中,Servlet[dispatcher]的Servlet.service()引发了具有根本原因的异常[Reque
st processing failed: java.lang.IllegalArgumentException: Name for argument of t
ype [java.lang.String] not specified, and parameter name information not availab
le via reflection. Ensure that the compiler uses the '-parameters' flag.]
java.lang.IllegalArgumentException: Name for argument of type [java.lang.String]
not specified, and parameter name information not available via reflection. Ens
ure that the compiler uses the '-parameters' flag.
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentRe
solver.updateNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:187)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentRe
solver.getNamedValueInfo(AbstractNamedValueMethodArgumentResolver.java:162)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentRe
solver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:108)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposit
e.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgum
entValues(InvocableHandlerMethod.java:224)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForReque
st(InvocableHandlerMethod.java:178)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandle
rMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter.handleInternal(RequestMappingHandlerAdapter.java:831)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapt
确保了依赖引入完全无漏项,Controller方法参数无拼写错误。
/**
* 用户输入账号及密码,请求登录
*
* @param loginAcc 账号
* @param loginPwd 密码
* @param isRemembered 是否记住密码
* @return
*/
@RequestMapping("/settings/qx/user/login.do")
@ResponseBody
public Object login(HttpServletRequest request, String loginAcc, String loginPwd, String isRemembered) {
//做了一些事情
}
用AI问了一下,提示Maven构建工具要添加==-parameters==选项,那就加上呗,实际上Maven的settings里面已经设置了。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
添加后又出现了另一个错误,实际上这个错误才是最主要的错误,在网上检索了很久才发现。
报错信息如下:
Servlet[dispatcher]的Servlet.service()引发了具有根本原因的异常[Reque
st processing failed: java.lang.IllegalStateException: No primary or single uniq
ue constructor found for interface javax.servlet.http.HttpServletRequest]
java.lang.IllegalStateException: No primary or single unique constructor found f
or interface javax.servlet.http.HttpServletRequest
at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:
265)
at org.springframework.validation.DataBinder.createObject(DataBinder.java:924)
at org.springframework.validation.DataBinder.construct(DataBinder.java:903)
at org.springframework.web.bind.ServletRequestDataBinder.construct(ServletReque
stDataBinder.java:116)
这个报错似乎在说Spring在想注入HttpServletRequest的时候没有找到,AI的回答具有很强的误导性,但是也给了我一些启发:
这个异常java.lang.IllegalStateException: No primary or single unique constructor found for interface javax.servlet.http.HttpServletRequest 是由于Spring框架在尝试为HttpServletRequest接口实例化一个对象时遇到的问题。但是,HttpServletRequest是一个接口,它不能被直接实例化,而应该由Servlet容器(如Tomcat, Jetty等)在HTTP请求到达时提供实现。
这个异常很可能是由于Spring框架的某个配置错误或误用导致的。这里有几个可能的原因和相应的解决方案:
错误的注解使用:你可能在某个地方错误地使用了@Autowired或其他Spring的注入注解来尝试注入HttpServletRequest。HttpServletRequest应该作为方法的参数,通过Spring的HandlerMethodArgumentResolver自动解析,而不是作为类的成员变量通过注解注入。
解决方法:将HttpServletRequest作为方法参数,而不是类成员变量。
错误的配置:可能在某个Spring配置类中,你尝试使用@Bean注解来创建一个HttpServletRequest的Bean,这是不正确的。
解决方法:移除或更正任何尝试创建HttpServletRequest Bean的配置。
原因分析:
Java Servlet API 是由 Sun Microsystems(现在是 Oracle)开发和维护的,其包名以 javax.servlet 开头。从 Java EE 8 开始,Servlet API 的维护权转交给了 Eclipse Foundation 的 Jakarta EE 社区,因此,在最新的 Jakarta EE 版本中,Servlet API 的包名已经更改为 jakarta.servlet。
Tomcat10以后的版本需要 jakarta.servlet,而不是javax.servlet
原文链接:javax.servlet 和 jakarta.servlet的关系和使用tomcat部署 jakarta.servlet
也就是我的依赖中Servlet导入的是javax.servlet-api,但是服务器却使用的是Tomcat10,而Tomcat10不再依赖javax.servlet-api,而是依赖jakarta.servlet-api,这个就是根本的原因:依赖导入的问题,但是报错信息以及AI的解答均有一定的迷惑性,所以走了一些弯路。
解决方案:
导入jakarta.servlet-api依赖替换javax.servlet-api
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
举一反三
在使用各类中间件的时候,必须考虑中间件的依赖,因为中间件的依赖可能存在一定的滞后性,如果遇到类似的报错,需要考虑到这一点。