SpringBoot+MyBatisPlus项目,非常简单,没有任何业务逻辑:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.7.12
org.yh.mall
mall-server
0.0.1-SNAPSHOT
mall-server
mall-server
1.8
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-groovy-templates
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
com.mysql
mysql-connector-j
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-validation
com.baomidou
mybatis-plus-boot-starter
3.5.3.1
com.alibaba
druid-spring-boot-starter
1.2.18
cn.hutool
hutool-all
5.8.19
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
src/main/resources
package gov.yh.mall;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(basePackages = {"gov.yh.mall"})
public class MallServerApplication {
public static void main(String[] args) {
SpringApplication.run(MallServerApplication.class, args);
}
}
package gov.yh.mall.controller;
import gov.yh.mall.common.api.ApiResp;
import gov.yh.mall.service.CategoryService;
import gov.yh.mall.vo.CategoryTreeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/category")
@RestController
public class CategoryController {
@Autowired
private CategoryService categoryService;
@GetMapping("/tree")
public ApiResp tree() {
return ApiResp.ok(categoryService.listTree());
}
}
package gov.yh.mall.service;
import com.baomidou.mybatisplus.extension.service.IService;
import gov.yh.mall.domain.Category;
import gov.yh.mall.vo.CategoryTreeVo;
public interface CategoryService extends IService {
CategoryTreeVo listTree();
}
package gov.yh.mall.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import gov.yh.mall.domain.Category;
import gov.yh.mall.mapper.CategoryMapper;
import gov.yh.mall.service.CategoryService;
import gov.yh.mall.vo.CategoryTreeVo;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImpl extends ServiceImpl implements CategoryService {
@Override
public CategoryTreeVo listTree() {
return null;
}
}
package gov.yh.mall.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public abstract class BaseDomain implements Serializable {
private static final long serialVersionUID = -4103484210920857803L;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime updateTime;
private String delFlag;
private Boolean status;
}
package gov.yh.mall.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import gov.yh.mall.common.utils.GenericListJsonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("mall_category")
public class Category extends BaseDomain implements Serializable {
private static final long serialVersionUID = 8072944985574611728L;
@TableId
private Integer categoryId;
private Integer parentId;
@TableField(typeHandler = GenericListJsonTypeHandler.class)
private List categoryPath;
private String categoryName;
}
package gov.yh.mall.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import gov.yh.mall.domain.Category;
import org.springframework.stereotype.Repository;
@Repository
public interface CategoryMapper extends BaseMapper {
}
与 mapper对应的xml放在resources/mapper目录中
CREATE TABLE `mall_category` (
`category_id` int(20) NOT NULL COMMENT 'ID',
`parent_id` int(20) DEFAULT NULL COMMENT '父级ID',
`category_path` json DEFAULT NULL COMMENT '类别全路径',
`category_name` varchar(30) COLLATE utf8mb4_bin NOT NULL COMMENT '类别名称',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` char(1) CHARACTER SET utf8mb4 DEFAULT '0' COMMENT '是否删除',
`status` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否启用的状态',
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='商品类目';
package gov.yh.mall.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class CategoryItem implements Serializable {
private static final long serialVersionUID = -251944196849206041L;
private Integer categoryId;
private Integer parentId;
private String categoryName;
}
package gov.yh.mall.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
public class CategoryTreeVo extends CategoryItem implements Serializable {
private static final long serialVersionUID = -5372664435944643984L;
private List children;
}
package gov.yh.mall.common.utils;
import cn.hutool.json.JSONUtil;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* JSON字段处理器,列表型数据
*
*/
public class GenericListJsonTypeHandler extends BaseTypeHandler> {
private final Class clazz;
public GenericListJsonTypeHandler(Class clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.clazz = clazz;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSONUtil.toJsonStr(parameter));
}
@Override
public List getNullableResult(ResultSet rs, String columnName) throws SQLException {
return this.toObject(rs.getObject(columnName), clazz);
}
@Override
public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return this.toObject(rs.getObject(columnIndex), clazz);
}
@Override
public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return this.toObject(cs.getObject(columnIndex), clazz);
}
private List toObject(Object content, Class clazz) {
if (content == null) {
return null;
}
return JSONUtil.toList(content.toString(), clazz);
}
}
server:
servlet:
encoding:
charset: UTF-8
enabled: true
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
aop:
proxy-target-class: true
auto: true
# 时间戳统一转换
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
type-aliases-package: com.wasu.mall
configuration:
# 驼峰转换 从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
server:
port: 10900
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/san-zhi?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
druid:
# druid监控全局配置
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config.multi-statement-allow: true
min-evictable-idle-time-millis: 300000
test-on-borrow: false
test-on-return: false
initial-size: 10
min-idle: 10
max-wait: 60000
pool-prepared-statements: true
test-while-idle: true
validation-query: select 1
time-between-eviction-runs-millis: 60000
max-pool-prepared-statement-per-connection-size: 20
max-active: 100
stat-view-servlet:
enabled: true
url-pattern: /druid/*
# redis 配置
redis:
host: 47.108.114.216
port: 6379
database: 1
password: fB5LX@NyFI
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 100ms
# 配置MyBatis日志
mybatis-plus:
configuration:
# 打印sql
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
package gov.yh.mall.mapper;
import cn.hutool.json.JSONUtil;
import gov.yh.mall.domain.Category;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.util.List;
@SpringBootTest
@ActiveProfiles({"dev"})
public class CategoryMapperTest {
@Autowired
private CategoryMapper categoryMapper;
@Test
public void testCategory() {
List categories = categoryMapper.selectList(null);
System.out.println(JSONUtil.toJsonPrettyStr(categories));
}
}
执行时,激活dev配置文件
请求接口/category/1,会调用CategoryController的getById方法,不调用CategoryService,调用成功
执行单元测试CategoryMapperTest,不调用CategoryService,直接调CategoryMapper,调用成功,没有任何错误
请求接口/category/tree,会调用CategoryController的tree方法,进而调用categoryService.listTree(),就会报错
2023-06-07 14:38:10.189 ERROR 34416 --- [io-10900-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): gov.yh.mall.service.CategoryService.listTree] with root cause
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): gov.yh.mall.service.CategoryService.listTree
at org.apache.ibatis.binding.MapperMethod$SqlCommand.(MapperMethod.java:235) ~[mybatis-3.5.10.jar:3.5.10]
at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.(MybatisMapperMethod.java:50) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.lambda$cachedInvoker$0(MybatisMapperProxy.java:111) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_302]
at com.baomidou.mybatisplus.core.toolkit.CollectionUtils.computeIfAbsent(CollectionUtils.java:115) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.cachedInvoker(MybatisMapperProxy.java:98) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
at com.sun.proxy.$Proxy77.listTree(Unknown Source) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_302]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_302]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_302]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_302]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.27.jar:5.3.27]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-5.3.27.jar:5.3.27]
at com.sun.proxy.$Proxy79.listTree(Unknown Source) ~[na:na]
at gov.yh.mall.controller.CategoryController.tree(CategoryController.java:29) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_302]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_302]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_302]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_302]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.27.jar:5.3.27]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.27.jar:5.3.27]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.27.jar:5.3.27]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) ~[tomcat-embed-core-9.0.75.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.27.jar:5.3.27]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) ~[tomcat-embed-core-9.0.75.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-9.0.75.jar:9.0.75]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.27.jar:5.3.27]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.27.jar:5.3.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.27.jar:5.3.27]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.27.jar:5.3.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.27.jar:5.3.27]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.27.jar:5.3.27]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.75.jar:9.0.75]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.75.jar:9.0.75]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_302]
总之,不知道哪里不对了,就一直有这个Invalid bound statement (not found),请大神给指点一下,到底哪里出问题了。
代码已经上传到Gitee了,地址:mall-check: 一个有问题的代码仓库