springboot项目启动访问任何html页面报类型转换错误:Failed to convert value of type...
问题:
2023-05-30T21:35:57.495+08:00 WARN 19900 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: "emp.html"]
2023-05-30T21:35:59.857+08:00 WARN 19900 --- [nio-8080-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: "emp.html"]
2023-05-30T21:36:19.137+08:00 WARN 19900 --- [nio-8080-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: "a.html"]
2023-05-30T21:36:21.158+08:00 WARN 19900 --- [io-8080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: "a.html"]
今天在启动一个springboot案例的,代码编译成功,postman测试结果也成功:
接下来我定义了一个emp.html页面将返回的json数据用vue渲染在这个页面上发现后台报错:
接着我尝试重启,用其他页面比如新建一个a.html静态页面访问还是报上面这个错误。于是我想是不是maven版本依赖的问题,发现mvn -v执行显示的maven版本对应的jdk版本是jdk1.8而使用java -version显示的版本又是jdk17。发现maven和jdk版本不匹配,于是我修改了jdk的环境变量使之匹配,这里注意jdk17安装后默认已经配置好了环境变量,因此即使你配了JAVA_HOME指定了jdk1.8的环境变量,cmd查看版本仍然还是17版。所以我要修改之前配置的1.8改成17并且将安装jdk17时自动生成的那个环境变量删除。这样maven和jdk就匹配了。
然后重新建立一个springboot程序,将原来的代码全部搬运到新的模块下,启动后再次访问emp.html页面发现还是报同样的错误,再访问a.html页面也是报同样的错误。这就奇怪了。postman测试工具可以访问我的接口方法,怎么html访问用axios触发接口方法就报错呢?真是百思不得其解,于是我打开html页面查看一下:
页面js代码是没有问题的。于是我怀疑是不是idea和maven配置没配好?于是我重新配置了在idea的maven,按照原来的步骤测试发现一样的问题。由于sprinrboot提示的是warn信息,我并不认为是错误,所以我没有打断点进行调试,我试着将别人同样的代码搬运到新建的springboot案例里面执行页面发现能正常返回。接着我就一直猜测是jar包的不兼容性导致的,实在没有办法确定问题所在了,我只好打断点调试,找到问题的类定位问题MethodArgumentTypeMismatchException,这个类是解析方法参数类型匹配异常的类,如果有参数匹配问题就会抛出异常,不过很奇怪springboot竟然将它作为警告信息显示,实际上应该是错误才对,这样开发者比较容易敏感定位问题。实际上所有的@RequestMapping注解的方法都会被
AbstractHandlerMethodAdapter
这个类的
getMethodArgumentValues
方法解析到,如果是一个页面没有带任何参数则会直接返回,但是如果是一个get请求并且带参数的话则会进入里面进行
resolveArgument
方法的参数解析,这个时候如果请求参数是字符串,而方法参数里面是非字符串比如Integer类型,这个时候就会报解析错误了:Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: "a.html"。那为什么我输入一个html的静态页面就会报这个错误呢,我仔细找了一下
MethodParameter[] parameters = this.getMethodParameters();
定位到里面的参数发现了有问题的方法所在的类RequestController以及接口映射方法pathParamJust,终于定位到了问题方法所在,发现这个方法我之前是用了一个路径参数作为测试 用的
方法上面的注解和路径参数: @RequestMapping("/{id}")。
@RequestMapping("/{id}")
public String pathParamJust(@PathVariable Integer id){
System.out.println(id);
return "OK";
}
方法参数是Integer ,这就有问题了,如果直接输入localhost:8080/emp.html,那其实/emp.html这个emp.html都会被当作路径字符进行匹配,因此就不会当作一个页面进行访问,也就不会进入到html的js里面进行ajax的请求,也就不会访问到真正的接口方法了。所以在需要用到路径参数的地方一定要注意路径参数类型与接口参数类型要一致,尽量使用默认的字符进行匹配,这样参数解析的时候,springmvc就知道你访问的是字符串还是一个页面,如果是页面则会解析成页面进行渲染如果是字符串就使用字符串作为参数,所以要注意参数类型的匹配。
实际上这个问题根本原因并不是服务器的错误,这根本就是前端请求参数的错误,说明应该将问题关注在请求参数或者请求路径上,比如路径参数与接口参数类型不匹配等。
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
由上面可以知道400这个错误类型是指:400 Bad Request 响应状态码指示服务器无法理解请求。客户不应未经修改就重复此请求。
这个问题足足查了有两天的时间,发现查问题的效率很低,我在这里总结一下。首先发现问题的时候不要直接就问百度或者Google,而是应该思考问题所在,为什么出现这样的问题。如果我一开始就打断点调试那这个问题肯定很快就解决了。所以我认为有问题尽量断点是比较快的选择。
其次如果问题还是不明确,或者断点调试不能定位到问题,那我觉得应该用层层递进的方法进行问题定位,比如去除一部分无关代码,就只纯用自己写的方法进行测试,比如我删除之前测试用的那个路径测试控制器类,再访问html页面就可以成功访问,一下子就可以将问题范围缩小甚至直接定位到问题。
总结就是,以后开发代码遇到问题要应采用断点调试加层层递进的测试方法进行问题定位。