spring boot 的接口form入参-字段映射别名

本文介绍了如何在Spring MVC接口开发中,解决因接口参数使用蟒蛇式命名而后端驼峰式接收的问题,通过自定义注解和属性编辑器实现自动参数转换及别名绑定。

接口开发,入参是使用的蟒蛇式(如:psn_name),而后端接收使用的是驼峰式(如psnName)。并且入参很多,使用spring 的 @RequestParam 只适用少量入参,需要自动进行参数转换。

参考

如何在绑定Spring MVC命令对象时自定义参数名称?
spring mvc给参数起别名
SpringMVC请求参数别名设置
SpringMVC 通过post接收form参数或者json参数
Spring boot 参数别名处理
springboot中使用servlet

实现代码

接口

/**
 * 如果是实体类,并且用到了注解ReqParamAs,请实现本类
 *
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
public interface ReqParamBean { }

注解

import java.lang.annotation.*;
/**请求的字段别名设置,通过自定义spring属性编辑器解决
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
@Target (ElementType.FIELD)
@Retention (RetentionPolicy.RUNTIME)
@Documented
public @interface ReqParamAs {
    String value();
}

自定义spring属性编辑器

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder;

import javax.servlet.ServletRequest;
import java.util.Map;

/**
 * 请求的字段别名-数据绑定处理,通过自定义spring属性编辑器解决
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
public class ReqParamAsDataBinder extends ExtendedServletRequestDataBinder {
    private static final Logger logger = LoggerFactory.getLogger(ReqParamAsDataBinder.class);
    private final Map<String, String> cacheMap;
    public ReqParamAsDataBinder(Object target,String objectName,Map<String, String> asMap){
        super(target,objectName);
        this.cacheMap = asMap;
    }
    /**
     * 复写addBindValues方法
     * @param mpv 这里面存的就是请求参数的key-value对
     * @param req 请求本身, 这里没有用到
     */
    @Override
    protected void addBindValues(@NotNull MutablePropertyValues mpv, @NotNull ServletRequest req) {
        super.addBindValues(mpv, req);
        Object obj;
        PropertyValue pv;
        logger.info("字段别名-缓存,{}",cacheMap);
        for (Map.Entry<String, String> entry : cacheMap.entrySet()) {
            String alias = entry.getKey(),fieldName = entry.getValue();
            if(mpv.contains(alias)){
                pv = mpv.getPropertyValue(alias);
                if( null == pv ){ continue; }
                obj = pv.getValue();
                logger.debug("字段别名-数据绑定处理,{}<>{},{}",alias,fieldName,obj);
                // 给原始字段赋值
                mpv.add(fieldName, obj);
            }
        }
    }
}

参数解析器

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import javax.servlet.ServletRequest;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 请求的字段别名-参数解析器,通过自定义spring属性编辑器解决
 *
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
public class ReqParamAsProcessor extends ServletModelAttributeMethodProcessor {
    private static final Map<Class<?>,Map<String, String>> PARAM_CACHE_MAP = new ConcurrentHashMap<>();
    private final ApplicationContext context;
    public ReqParamAsProcessor(ApplicationContext applicationContext){
        super(true);
        this.context = applicationContext;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 接口方法不含 注解 RequestParam、入参不是 简单参数、并且参数对象内的字段包含自定义注解 RequestParam
        return !parameter.hasParameterAnnotation(RequestParam.class)
            && !parameter.hasParameterAnnotation(RequestBody.class)
            && !BeanUtils.isSimpleProperty(parameter.getParameterType())
            && Arrays.stream(parameter.getParameterType().getDeclaredFields())
                .anyMatch(field -> field.getAnnotation(ReqParamAs.class) != null);
    }

    @Override
    protected void bindRequestParameters(@NotNull WebDataBinder binder, @NotNull NativeWebRequest request) {
        Map<String, String> asMap = cacheMap(Objects.requireNonNull(binder.getTarget()).getClass());
        ReqParamAsDataBinder dataBinder = new ReqParamAsDataBinder(binder.getTarget(),binder.getObjectName(),asMap);
        RequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class);
        Objects.requireNonNull(adapter.getWebBindingInitializer()).initBinder(dataBinder);
        dataBinder.bind(Objects.requireNonNull(request.getNativeRequest(ServletRequest.class)));
        super.bindRequestParameters(binder, request);
    }
    private Map<String, String> cacheMap(Class<?> target){
        if(PARAM_CACHE_MAP.containsKey(target)){
            return PARAM_CACHE_MAP.get(target);
        }
        Map<String, String> map = analyzeClass(target,"","");
        PARAM_CACHE_MAP.put(target,map);
        return map;
    }
    private Map<String, String> analyzeClass(Class<?> target,String prtAs,String prtField){
        Field[] fields = target.getDeclaredFields();
        Map<String, String> map = new HashMap<>(fields.length);
        ReqParamAs rpa;
        boolean boo;
        String as;
        for (Field field : fields) {
            boo = (null == (rpa = field.getAnnotation(ReqParamAs.class)) || rpa.value().isEmpty());
            as = boo ? field.getName() : rpa.value();
            if( isExtendBean(field.getType().getInterfaces()) ){
                //如果字段类实现了自定义接口,就认为是自定义是对象类,继续解析字段
                // 通过自定义注解在类上面使用,在这里判断也可以
                map.putAll(analyzeClass(field.getType(),prtAs + as + '.',prtField + field.getName() + '.'));
            }else if( !boo || !"".equals(prtAs)){
               // 只绑定需要的映射
                map.put(prtAs + as,prtField + field.getName());
            }
        }
        return map;
    }
    private boolean isExtendBean(Class<?>[] interfaces){
        for (Class<?> face : interfaces) {
            if(face == ReqParamBean.class){ return true; }
        }
        return false;
    }
}

注入spring


import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * 请求的字段别名-参数解析器 添加到第一个参数解析器中的bean配置,通过自定义spring属性编辑器解决
 *
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
@Configuration
public class ReqParamAsConfig {
    private ApplicationContext applicationContext;
    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Bean
    public ReqParamAsProcessor reqParamAsProcessor(){
        return new ReqParamAsProcessor(applicationContext);
    }
    @Bean
    public BeanPostProcessor beanPostProcessor(){
        return new BeanPostProcessor() {
            @Override
            public Object postProcessBeforeInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException {
                return bean;
            }
            @Override
            public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException {
                if(bean instanceof RequestMappingHandlerAdapter){
                    RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter)bean;
                    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
                    resolvers.add(reqParamAsProcessor());
                    if(adapter.getArgumentResolvers() != null){
                        resolvers.addAll(adapter.getArgumentResolvers());
                    }
                    adapter.setArgumentResolvers(resolvers);
                }
                return bean;
            }
        };
    }
}

测试代码

实体类-使用别名注解

import ...annotation.ReqParamAs;
import ...annotation.ReqParamBean;

/**
 * 测试类
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
public class TestAsBean {
    private String name;
    private Integer age;
    @ReqParamAs ("psn_name")
    private String psnName;
    private Integer psnAge;
    @ReqParamAs (value = "my_dog")
    private Dog dog;
    public static class Dog implements ReqParamBean {
        private String dogName;
    	@ReqParamAs ("dog_age")
        private Integer dogAge;
        public String getDogName() { return dogName; }
        public void setDogName(String dogName) { this.dogName = dogName; }
        public Integer getDogAge() { return dogAge; }
        public void setDogAge(Integer dogAge) { this.dogAge = dogAge; }
        @Override
        public String toString() {
            return "{dogName='" + dogName + "', dogAge=" + dogAge + '}';
        }
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    public String getPsnName() { return psnName; }
    public void setPsnName(String psnName) { this.psnName = psnName; }
    public Integer getPsnAge() { return psnAge; }
    public void setPsnAge(Integer psnAge) { this.psnAge = psnAge; }
    public Dog getDog() { return dog; }
    public void setDog(Dog dog) { this.dog = dog; }
    @Override
    public String toString() {
        return "{name='" + name + "', age=" + age + ", psnName='" + psnName + "', psnAge=" + psnAge + ", dog=" + dog + '}';
    }
}

测试接口

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author z.y
 * @version v1.0
 * @date 2022/6
 */
@RestController
@RequestMapping ("test/as")
public class TestAsController {
    private static final Logger logger = LoggerFactory.getLogger(TestAsController.class);
    @PostMapping (value = "root")
    public TestAsBean root(TestAsBean bean){
        logger.info("测试字段别名,{}",bean);
        bean.setName("你说啥");
        return bean;
    }
}

测试记录

未使用别名

http://localhost:8092/test/as/root
age=1&dog.dogAge=2&dog.dogName=%E7%AD%89%E5%BE%85&name=%E5%95%8A%E5%95%8A&psnAge=4&psnName=%E5%A4%9A%E5%A4%A7

2022-06-15 18:22:39.211 - [] - [http-nio-8092-exec-5] INFO  ...controller.TestAsController.root(20) - 测试字段别名,{name='啊啊', age=1, psnName='多大', psnAge=4, dog={dogName='等待', dogAge=2}}

在这里插入图片描述

使用别名

http://localhost:8092/test/as/root
age=1&my_dog.dog_age=2&dog.dogName=%E7%AD%89%E5%BE%85&name=%E5%95%8A%E5%95%8A&psnAge=4&psn_name=%E5%A4%9A%E5%A4%A7

2022-06-17 14:29:39.782 - INFO  .annotation.ReqParamAsDataBinder.addBindValues(37) - 字段别名-缓存,{my_dog.dog_age=dog.dogAge, psn_name=psnName, my_dog.dogName=dog.dogName}
2022-06-17 14:29:39.783 - DEBUG .annotation.ReqParamAsDataBinder.addBindValues(44) - 字段别名-数据绑定处理,my_dog.dog_age<>dog.dogAge,2
2022-06-17 14:29:39.785 - DEBUG .annotation.ReqParamAsDataBinder.addBindValues(44) - 字段别名-数据绑定处理,psn_name<>psnName,多大
2022-06-17 14:29:40.057 - INFO  .controller.TestAsController.root(20) - 测试字段别名,{name='啊啊', age=1, psnName='多大', psnAge=4, dog={dogName='等待', dogAge=2}}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题-已解决

当前级联别名,暂未处理,记录debug截图,有时间调整代码逻辑实现。
在这里插入图片描述

D:\jkd17\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:E:\idea\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar=57906:E:\idea\IntelliJ IDEA 2021.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-launcher\1.12.2\junit-platform-launcher-1.12.2.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-engine\1.12.2\junit-platform-engine-1.12.2.jar;C:\Users\Administrator\.m2\repository\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;C:\Users\Administrator\.m2\repository\org\junit\platform\junit-platform-commons\1.12.2\junit-platform-commons-1.12.2.jar;C:\Users\Administrator\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;E:\idea\IntelliJ IDEA 2021.3.3\lib\idea_rt.jar;E:\idea\IntelliJ IDEA 2021.3.3\plugins\junit\lib\junit5-rt.jar;E:\idea\IntelliJ IDEA 2021.3.3\plugins\junit\lib\junit-rt.jar;E:\ruoyi\gulimall-01\gulimall-product\target\test-classes;E:\ruoyi\gulimall-01\gulimall-product\target\classes;E:\ruoyi\gulimall-01\gulimall-common\target\classes;D:\Maven\crmrepo\org\projectlombok\lombok\1.18.38\lombok-1.18.38.jar;D:\Maven\crmrepo\com\baomidou\mybatis-plus-boot-starter\3.3.1.tmp\mybatis-plus-boot-starter-3.3.1.tmp.jar;D:\Maven\crmrepo\com\baomidou\mybatis-plus\3.3.1.tmp\mybatis-plus-3.3.1.tmp.jar;D:\Maven\crmrepo\com\baomidou\mybatis-plus-extension\3.3.1.tmp\mybatis-plus-extension-3.3.1.tmp.jar;D:\Maven\crmrepo\com\baomidou\mybatis-plus-core\3.3.1.tmp\mybatis-plus-core-3.3.1.tmp.jar;D:\Maven\crmrepo\com\baomidou\mybatis-plus-annotation\3.3.1.tmp\mybatis-plus-annotation-3.3.1.tmp.jar;D:\Maven\crmrepo\com\github\jsqlparser\jsqlparser\3.1\jsqlparser-3.1.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-autoconfigure\3.5.4\spring-boot-autoconfigure-3.5.4.jar;D:\Maven\crmrepo\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;D:\Maven\crmrepo\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\Maven\crmrepo\com\mysql\mysql-connector-j\9.3.0\mysql-connector-j-9.3.0.jar;D:\Maven\crmrepo\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter-web\3.5.4\spring-boot-starter-web-3.5.4.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter\3.5.4\spring-boot-starter-3.5.4.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot\3.5.4\spring-boot-3.5.4.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter-logging\3.5.4\spring-boot-starter-logging-3.5.4.jar;D:\Maven\crmrepo\ch\qos\logback\logback-classic\1.5.18\logback-classic-1.5.18.jar;D:\Maven\crmrepo\ch\qos\logback\logback-core\1.5.18\logback-core-1.5.18.jar;D:\Maven\crmrepo\org\apache\logging\log4j\log4j-to-slf4j\2.24.3\log4j-to-slf4j-2.24.3.jar;D:\Maven\crmrepo\org\apache\logging\log4j\log4j-api\2.24.3\log4j-api-2.24.3.jar;D:\Maven\crmrepo\org\slf4j\jul-to-slf4j\2.0.17\jul-to-slf4j-2.0.17.jar;D:\Maven\crmrepo\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;D:\Maven\crmrepo\org\yaml\snakeyaml\2.4\snakeyaml-2.4.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter-json\3.5.4\spring-boot-starter-json-3.5.4.jar;D:\Maven\crmrepo\com\fasterxml\jackson\core\jackson-databind\2.19.2\jackson-databind-2.19.2.jar;D:\Maven\crmrepo\com\fasterxml\jackson\core\jackson-annotations\2.19.2\jackson-annotations-2.19.2.jar;D:\Maven\crmrepo\com\fasterxml\jackson\core\jackson-core\2.19.2\jackson-core-2.19.2.jar;D:\Maven\crmrepo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.19.2\jackson-datatype-jdk8-2.19.2.jar;D:\Maven\crmrepo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.19.2\jackson-datatype-jsr310-2.19.2.jar;D:\Maven\crmrepo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.19.2\jackson-module-parameter-names-2.19.2.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter-tomcat\3.5.4\spring-boot-starter-tomcat-3.5.4.jar;D:\Maven\crmrepo\org\apache\tomcat\embed\tomcat-embed-core\10.1.43\tomcat-embed-core-10.1.43.jar;D:\Maven\crmrepo\org\apache\tomcat\embed\tomcat-embed-el\10.1.43\tomcat-embed-el-10.1.43.jar;D:\Maven\crmrepo\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.43\tomcat-embed-websocket-10.1.43.jar;D:\Maven\crmrepo\org\springframework\spring-web\6.2.9\spring-web-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-beans\6.2.9\spring-beans-6.2.9.jar;D:\Maven\crmrepo\io\micrometer\micrometer-observation\1.15.2\micrometer-observation-1.15.2.jar;D:\Maven\crmrepo\io\micrometer\micrometer-commons\1.15.2\micrometer-commons-1.15.2.jar;D:\Maven\crmrepo\org\springframework\spring-webmvc\6.2.9\spring-webmvc-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-aop\6.2.9\spring-aop-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-context\6.2.9\spring-context-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-expression\6.2.9\spring-expression-6.2.9.jar;D:\Maven\crmrepo\org\springframework\cloud\spring-cloud-starter-openfeign\4.3.0\spring-cloud-starter-openfeign-4.3.0.jar;D:\Maven\crmrepo\org\springframework\cloud\spring-cloud-starter\4.3.0\spring-cloud-starter-4.3.0.jar;D:\Maven\crmrepo\org\springframework\cloud\spring-cloud-context\4.3.0\spring-cloud-context-4.3.0.jar;D:\Maven\crmrepo\org\bouncycastle\bcprov-jdk18on\1.80\bcprov-jdk18on-1.80.jar;D:\Maven\crmrepo\org\springframework\cloud\spring-cloud-openfeign-core\4.3.0\spring-cloud-openfeign-core-4.3.0.jar;D:\Maven\crmrepo\io\github\openfeign\feign-form-spring\13.6\feign-form-spring-13.6.jar;D:\Maven\crmrepo\org\apache\commons\commons-text\1.13.0\commons-text-1.13.0.jar;D:\Maven\crmrepo\org\apache\commons\commons-lang3\3.17.0\commons-lang3-3.17.0.jar;D:\Maven\crmrepo\io\github\openfeign\feign-form\13.6\feign-form-13.6.jar;D:\Maven\crmrepo\commons-fileupload\commons-fileupload\1.5\commons-fileupload-1.5.jar;D:\Maven\crmrepo\org\springframework\cloud\spring-cloud-commons\4.3.0\spring-cloud-commons-4.3.0.jar;D:\Maven\crmrepo\org\springframework\security\spring-security-crypto\6.5.2\spring-security-crypto-6.5.2.jar;D:\Maven\crmrepo\io\github\openfeign\feign-core\13.6\feign-core-13.6.jar;D:\Maven\crmrepo\io\github\openfeign\feign-slf4j\13.6\feign-slf4j-13.6.jar;D:\Maven\crmrepo\org\slf4j\slf4j-api\2.0.17\slf4j-api-2.0.17.jar;D:\Maven\crmrepo\org\mybatis\spring\boot\mybatis-spring-boot-starter\3.0.3\mybatis-spring-boot-starter-3.0.3.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter-jdbc\3.5.4\spring-boot-starter-jdbc-3.5.4.jar;D:\Maven\crmrepo\com\zaxxer\HikariCP\6.3.1\HikariCP-6.3.1.jar;D:\Maven\crmrepo\org\springframework\spring-jdbc\6.2.9\spring-jdbc-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-tx\6.2.9\spring-tx-6.2.9.jar;D:\Maven\crmrepo\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\3.0.3\mybatis-spring-boot-autoconfigure-3.0.3.jar;D:\Maven\crmrepo\org\mybatis\mybatis\3.5.14\mybatis-3.5.14.jar;D:\Maven\crmrepo\org\mybatis\mybatis-spring\3.0.3\mybatis-spring-3.0.3.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-starter-test\3.5.4\spring-boot-starter-test-3.5.4.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-test\3.5.4\spring-boot-test-3.5.4.jar;D:\Maven\crmrepo\org\springframework\boot\spring-boot-test-autoconfigure\3.5.4\spring-boot-test-autoconfigure-3.5.4.jar;D:\Maven\crmrepo\com\jayway\jsonpath\json-path\2.9.0\json-path-2.9.0.jar;D:\Maven\crmrepo\jakarta\xml\bind\jakarta.xml.bind-api\4.0.2\jakarta.xml.bind-api-4.0.2.jar;D:\Maven\crmrepo\jakarta\activation\jakarta.activation-api\2.1.3\jakarta.activation-api-2.1.3.jar;D:\Maven\crmrepo\net\minidev\json-smart\2.5.2\json-smart-2.5.2.jar;D:\Maven\crmrepo\net\minidev\accessors-smart\2.5.2\accessors-smart-2.5.2.jar;D:\Maven\crmrepo\org\ow2\asm\asm\9.7.1\asm-9.7.1.jar;D:\Maven\crmrepo\org\assertj\assertj-core\3.27.3\assertj-core-3.27.3.jar;D:\Maven\crmrepo\net\bytebuddy\byte-buddy\1.17.6\byte-buddy-1.17.6.jar;D:\Maven\crmrepo\org\awaitility\awaitility\4.2.2\awaitility-4.2.2.jar;D:\Maven\crmrepo\org\hamcrest\hamcrest\3.0\hamcrest-3.0.jar;D:\Maven\crmrepo\org\junit\jupiter\junit-jupiter\5.12.2\junit-jupiter-5.12.2.jar;D:\Maven\crmrepo\org\junit\jupiter\junit-jupiter-api\5.12.2\junit-jupiter-api-5.12.2.jar;D:\Maven\crmrepo\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;D:\Maven\crmrepo\org\junit\platform\junit-platform-commons\1.12.2\junit-platform-commons-1.12.2.jar;D:\Maven\crmrepo\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;D:\Maven\crmrepo\org\junit\jupiter\junit-jupiter-params\5.12.2\junit-jupiter-params-5.12.2.jar;D:\Maven\crmrepo\org\junit\jupiter\junit-jupiter-engine\5.12.2\junit-jupiter-engine-5.12.2.jar;D:\Maven\crmrepo\org\junit\platform\junit-platform-engine\1.12.2\junit-platform-engine-1.12.2.jar;D:\Maven\crmrepo\org\mockito\mockito-core\5.17.0\mockito-core-5.17.0.jar;D:\Maven\crmrepo\net\bytebuddy\byte-buddy-agent\1.17.6\byte-buddy-agent-1.17.6.jar;D:\Maven\crmrepo\org\objenesis\objenesis\3.3\objenesis-3.3.jar;D:\Maven\crmrepo\org\mockito\mockito-junit-jupiter\5.17.0\mockito-junit-jupiter-5.17.0.jar;D:\Maven\crmrepo\org\skyscreamer\jsonassert\1.5.3\jsonassert-1.5.3.jar;D:\Maven\crmrepo\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;D:\Maven\crmrepo\org\springframework\spring-core\6.2.9\spring-core-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-jcl\6.2.9\spring-jcl-6.2.9.jar;D:\Maven\crmrepo\org\springframework\spring-test\6.2.9\spring-test-6.2.9.jar;D:\Maven\crmrepo\org\xmlunit\xmlunit-core\2.10.3\xmlunit-core-2.10.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 com.mqt.gulimall.product.GulimallProductApplicationTests,testSaveBrandEntity1 08:57:36.263 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.mqt.gulimall.product.GulimallProductApplicationTests]: GulimallProductApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. 08:57:36.466 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.mqt.gulimall.product.GulimallProductApplication for test class com.mqt.gulimall.product.GulimallProductApplicationTests . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.5.4) 2025-08-16T08:57:37.963+08:00 INFO 2708 --- [ main] c.m.g.p.GulimallProductApplicationTests : Starting GulimallProductApplicationTests using Java 17.0.16 with PID 2708 (started by Administrator in E:\ruoyi\gulimall-01\gulimall-product) 2025-08-16T08:57:37.965+08:00 INFO 2708 --- [ main] c.m.g.p.GulimallProductApplicationTests : No active profile set, falling back to 1 default profile: "default" 2025-08-16T08:57:39.841+08:00 INFO 2708 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=b9e0ec63-ed6c-34d9-b3e4-ff50d76ad705 2025-08-16T08:57:40.861+08:00 INFO 2708 --- [ main] o.s.v.b.OptionalValidatorFactoryBean : Failed to set up a Bean Validation provider: jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found. Add a provider like Hibernate Validator (RI) to your classpath. 2025-08-16T08:57:41.619+08:00 INFO 2708 --- [ main] c.m.g.p.GulimallProductApplicationTests : Started GulimallProductApplicationTests in 4.37 seconds (process running for 6.674) OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended java.lang.RuntimeException: 保存品牌实体失败 at com.mqt.gulimall.product.service.impl.BrandServiceImpl.saveone(BrandServiceImpl.java:47) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:360) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:724) at com.mqt.gulimall.product.service.impl.BrandServiceImpl$$SpringCGLIB$$0.saveone(<generated>) at com.mqt.gulimall.product.GulimallProductApplicationTests.testSaveBrandEntity1(GulimallProductApplicationTests.java:26) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Caused by: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.mqt.gulimall.product.dao.BrandDao.insertinto at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:229) at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53) at org.apache.ibatis.binding.MapperProxy.lambda$cachedInvoker$0(MapperProxy.java:96) at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) at org.apache.ibatis.util.MapUtil.computeIfAbsent(MapUtil.java:36) at org.apache.ibatis.binding.MapperProxy.cachedInvoker(MapperProxy.java:94) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) at jdk.proxy2/jdk.proxy2.$Proxy73.insertinto(Unknown Source) at com.mqt.gulimall.product.service.impl.BrandServiceImpl.saveone(BrandServiceImpl.java:43) ... 11 more Process finished with exit code -1
最新发布
08-17
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值