Spring mvc的问题:注释驱动

时间:2019-03-08 11:01:21

标签: java spring

我有一个类似

的控制器
@RequestMapping(value = {TABLE_URL}, method = RequestMethod.POST)
@ResponseBody
public TableModel checkAvailability(@ModelAttribute TableQueryForm TableQueryForm, 
        TableContext table, BindingResult bindingResult) throws Exception {
    // body
}

TableContext是具有实现及其正常工作的接口。

最近我需要添加一个自定义日期格式化程序,因此在将其启用后,我添加了行

<mvc:annotation-driven conversion-service="conversionService"/>

here

现在添加此内容后,我的请求失败,出现以下异常

Wrapped by: java.lang.IllegalStateException: No primary or default constructor found for interface com.table.domain.search.TableContext
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:212)
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:84)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:132)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

此类的实现未定义构造函数,因此默认情况下应激活默认的构造函数。我不知道为什么会这样。请帮助我解决这个问题。

4 个答案:

答案 0 :(得分:3)

如果不提供适当的HandlerMethodArgumentResolver,则无法在spring handler中注入自定义的Java接口。请注意“ custom”一词,因为Spring可以注入其他接口的实现,例如HttpServletRequest,HttpServletResponse,Reader,Writer等。在这些情况下,Spring注入适当的具体实现。对于自定义的Java类(如果仅是interface),从您得到的错误的stacktrace中可以看出不可能的原因。如果您的接口没有自定义处理程序解析器,则解析逻辑将在默认的ModelAttributeMethodProcessor上回退,该模型将在所有情况下都为上述接口类查找一个构造函数,但是由于在Java中该接口无法具有构造函数,因此它将失败(请注意带有FAILS的行)在这里)

public class ModelAttributeMethodProcessor {

protected Object createAttribute(String attributeName, MethodParameter parameter,
            WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {

        MethodParameter nestedParameter = parameter.nestedIfOptional();
        Class<?> clazz = nestedParameter.getNestedParameterType();

        Constructor<?> ctor = BeanUtils.findPrimaryConstructor(clazz);
        if (ctor == null) {
            Constructor<?>[] ctors = clazz.getConstructors();
            if (ctors.length == 1) {
                ctor = ctors[0];
            }
            else {
                try {
                    ctor = clazz.getDeclaredConstructor(); // FAILS HERE
                }
                catch (NoSuchMethodException ex) {
                    throw new IllegalStateException("No primary or default constructor found for " + clazz, ex);
                }
            }
        }
......................................
......................................

我尝试了以下测试课程

public interface TestInterface {    
    public void test() ;
}

@Component
public class TestInterfaceImpl implements TestInterface {

    @Override
    public void test() {
        System.out.println("Test called");      
    }

}

如果我的测试控制器是

 @RestController
    @RequestMapping("/test")
    public class TestController {   

        @GetMapping("test")
        public String withParam(TestInterface testInterface) {
            return "test";
        }

我和你遇到同样的错误

Caused by: java.lang.IllegalStateException: No primary or default constructor found for interface com.shailendra.TestInterface
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:212)
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:84)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:132)

但是如果我在下面使用

@RestController
@RequestMapping("/test")
public class TestController {   

    @GetMapping("test")
    public String withParam(TestInterfaceImpl test) {
        return "test";
    }

我得到了适当的答复。

如果接口注入有效,那么看起来您早先已经配置了适当的HandlerMethodArgumentResolver,但是由于某种原因,现在它没有被使用(也许是因为配置未包含在弹簧扫描中)

答案 1 :(得分:1)

需要一个空的构造函数来通过持久性框架的反射来创建新实例。如果不为该类的任何其他构造函数提供参数,则无需提供空的构造函数,因为默认情况下会得到一个。 @ u6f6o

您可能正在提供其他构造函数,因此您也应该尝试实现一个空的构造函数。

答案 2 :(得分:1)

您正在使用Java批注配置还是XML配置,如果您正在使用Java批注配置,那么您要做的就是删除XML配置文件以使其再次工作。

如果这不能解决您的问题,请提供您的配置和控制器类,以帮助解决问题。

答案 3 :(得分:0)

我建立了一个像您一样的项目,并且效果很好,但是我不知道您的bean中有哪些属性。 您可以根据实际代码进行调整

public interface TableContext {

    Long getDate();
}

public class TableContextImpl implements TableContext{

    private Long date;

    private String tableName;
    //getter setter ...
}

控制器

public String testOne(@RequestParam("tableContext") TableContext tableContext)

配置

    <context:annotation-config/>

    <context:component-scan base-package="com.test.controller"/>

    <mvc:annotation-driven conversion-service="conversionService"/>

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="tableContextFormatter"/>
           </set>
        </property>
    </bean>

    //this one is your custom formatter
    <bean id="tableContextFormatter" class="com.test.controller.TableContextFormatter"></bean>

格式化程序

public class TableContextFormatter implements Converter<String, TableContext> {


    @Override
    public TableContext convert(String s) {
        TableContext tc = null;
        if ( null != s ){
            tc = new TableContextImpl();
            //your formatting rules here
            ((TableContextImpl) tc).setDate(Long.parseLong(s));
        }
    return tc;
    }

}