【问题标题】:DispatcherServlet noHandlerFoundDispatcherServlet noHandlerFound
【发布时间】:2015-11-26 21:51:14
【问题描述】:

我一直在使用 Spring MVC 4/hibernate 4 和带有 Java 配置的 Web flow 2.4 构建应用程序。我已经使用 JUnits 构建和测试了服务和 daos,但是将 WebFlow 组件添加到应用程序中却一无所获。

我将控制器连同 CoreContextConfiguration 一起移到了核心包中,却一无所获。 LoginController 在 WEB-INF/flows 中有一个对应的 login.jsp 和一个 login-flow.xml 我希望 Spring Webflow 处理控制器,并且可以根据需要显示更多配置代码。我知道我错过了一些东西,可以用新的眼光来看待这个问题。

@EnableWebMvc//added
@Configuration
@Import({
    ServiceConfiguration.class, 
    FlowConfiguration.class,
    WebMVCConfiguration.class,
    DAOConfiguration.class
})
@ComponentScan("org.tigersndragons.salonbooks.model")
public class CoreContextConfiguration {

INFO: Server startup in 12640 ms
Jun 02, 2014 3:14:43 PM org.springframework.web.servlet.DispatcherServlet noHandlerFound
WARNING: No mapping found for HTTP request with URI [/salonbooks/login] in DispatcherServlet with name 'salonbooks'

我在尝试从

访问应用程序时收到上述错误
localhost:8080/salonbooks/login

如果我将 LoginController 显式导入到 CoreConfiguration,我会得到

javax.servlet.ServletException: No adapter for handler [org.tigersndragons.salonbooks.core.LoginController@20bd9af4]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler

下面是控制器sn-p

-- 更新为从配置中移除控制器

@Controller
public class LoginController extends AbstractController{
    @Autowired
    LoginActionFlows loginActionFlows;

    @RequestMapping(value="/login", method=RequestMethod.GET)
    public String showLogin(Model model){
        model.addAttribute("employee", new Employee());
        return "login";//new ModelAndView("index","employee", model);
    }

    @RequestMapping(value="/", method=RequestMethod.GET)
    public String index(Model model){

        return showLogin( model);//new ModelAndView("index","employee", model);
    }

web.xml 看起来像

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">    
    <display-name>SalonBooks</display-name>        
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>org.tigersndragons.salonbooks.core.CoreContextConfiguration</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>salonbooks</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>            
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>                        
        </init-param>            
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>salonbooks</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
    </welcome-file-list>    
</web-app>

--

流配置

@Configuration
public class FlowConfiguration extends AbstractFlowConfiguration{

@Autowired 
WebMVCConfiguration webMVCConfiguration;

@Bean
public FlowExecutor flowExecutor() {
    return getFlowExecutorBuilder(flowRegistry())
            .build();
}

@Bean 
public FlowController flowController (){
    FlowController flowController = new FlowController();
    flowController.setFlowExecutor(flowExecutor());
                flowController.setFlowHandlerAdapter(webMVCConfiguration.flowHandlerAdapter());
    return flowController;
}

//updated flowRegistry to specify the specific flow files
@Bean
public FlowDefinitionRegistry flowRegistry() {
    return getFlowDefinitionRegistryBuilder(flowBuilderServices())
            //.setBasePath("/WEB-INF/flows")
            //.addFlowLocationPattern("/**/*-flow.xml")
            .addFlowLocation("/WEB-INF/flows/login-flow.xml","login")
            .addFlowLocation("/WEB-INF/flows/home/home-flow.xml","home")
            .addFlowLocation("/WEB-INF/flows/person/person-flow.xml","person")
            .addFlowLocation("/WEB-INF/flows/appointment/appointment-flow.xml","appointment")
            .addFlowLocation("/WEB-INF/flows/order/order-flow.xml","order")
            .build();
}

@Bean
public FlowBuilderServices flowBuilderServices() {
    return getFlowBuilderServicesBuilder()
            .setViewFactoryCreator(mvcViewFactoryCreator())
            .setValidator(validator())
            .setDevelopmentMode(true)
            .build();
}

@Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
    MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
    factoryCreator.setDefaultViewSuffix(".jsp");
    factoryCreator.setViewResolvers(Arrays.<ViewResolver>asList(webMVCConfiguration.viewResolver()));
    factoryCreator.setUseSpringBeanBinding(true);
    return factoryCreator;
}

@Bean
public LocalValidatorFactoryBean validator() {
    return new LocalValidatorFactoryBean();
}

WebMVC配置

@Configuration
public class WebMVCConfiguration extends WebMvcConfigurerAdapter {

@Autowired
private FlowConfiguration webFlowConfig;
/*  updated this by commenting out
@Bean 
public ControllerClassNameHandlerMapping controllerClassNameHandlerMapping(){
    ControllerClassNameHandlerMapping mapping  =  new ControllerClassNameHandlerMapping();
     mapping.setPathPrefix("/flows");
    return mapping;
}
*/

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/", "classpath:/META-INF/web-resources/");
}

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
// updated this method to do nothing    
//      registry.addViewController("/");
//      registry.addViewController("/login");
//      registry.addViewController("/home");
//      registry.addViewController("/person");
}

@Bean
public FlowHandlerMapping flowHandlerMapping() {
    FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
    handlerMapping.setOrder(-1);
    handlerMapping.setFlowRegistry(webFlowConfig.flowRegistry());
    return handlerMapping;
}

@Bean
public FlowHandlerAdapter flowHandlerAdapter() {
    FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
    handlerAdapter.setFlowExecutor(webFlowConfig.flowExecutor());
    handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
    return handlerAdapter;
}

@Bean
public SalonFlowHandler SalonFlowHandler() {
    return new SalonFlowHandler();
}

/*added urlMappings*/

@Bean 
public SimpleUrlHandlerMapping urlMappings(){
    SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
    Properties urlProperties = new Properties();
    urlProperties.put("/*", webFlowConfig.flowController());
    urlProperties.put("/login", webFlowConfig.flowController());
    urlProperties.put("/home", webFlowConfig.flowController());
    urlProperties.put("/person", webFlowConfig.flowController());
    urlProperties.put("/appointment", webFlowConfig.flowController());
    urlProperties.put("/order", webFlowConfig.flowController());
    simpleUrlHandlerMapping.setMappings(urlProperties);
    simpleUrlHandlerMapping.setAlwaysUseFullPath(true);
    return simpleUrlHandlerMapping;
}

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setPrefix("/WEB-INF/flows/");
    viewResolver.setSuffix(".jsp");
    return viewResolver;
}

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<html>
<head>
    <meta charset="utf-8">
    <title>Welcome to SalonBooks</title>
</head> 
<body>
<div>Welcome to SalonBooks!!</div>

    <form:form id="login" model="loginActionFlows" 
    action="${flowExecutionUrl}" >
    <input type="hidden" name ="_flowExecutionKey"
    value="${flowExecutionKey}" />
    User: <br/><form:input type="text" path="username" /><br/>
    Passcode: <br/><form:input type="password" path="password"/><br/>
     <input name="_eventId_doLogin" type="submit" value="Login"/> | 
     <input type="button" name="_eventId_cancel" value="Cancel" />
    </form:form>
</body>
</html>

login-flow.xml 更新以指定视图和模型

<flow xmlns="http://www.springframework.org/schema/webflow"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/webflow 
  http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
   start-state="login">
<var name="loginActionFlows" class="org.tigersndragons.salonbooks.model.flows.LoginActionFlows"/>

<view-state id="login" view="login" model="loginActionFlows">

    <transition on="doLogin" to="verifylogin" />
    <transition on="cancel" to="done" />
</view-state>

<action-state id="verifylogin">
    <evaluate result ="employee" expression="loginActionFlows.checkEmployee(requestParameters.username, requestParameters.password)"/>

    <transition to ="home" />
</action-state>

<subflow-state id="home" subflow="home-flow">
    <transition to="finish" />
</subflow-state>

<end-state id="finish"/>

</flow>

现在这只是生成 login.jsp 的干式 /text 再现,而不是呈现为 html。所以它似乎开始了流程,但缺少渲染。

【问题讨论】:

  • 尝试删除extends AbstractController
  • 问题:你是如何在流配置类中指定流处理适配器的?
  • 添加了文件夹结构的屏幕截图
  • 不,它似乎没有执行 web 流。我有一段时间可以让视图显示并看到它尝试登录,但随后收到 SpelEvaluationExceptions 它不理解或找不到处于操作状态的属性。在 web.xml 中将 servlet-mapping 设置为“/”与“/*”是查看 jsp 和查看原始 jsp 文本之间的区别。

标签: java spring spring-mvc spring-webflow


【解决方案1】:

我怀疑 WebMVCConfiguration 中的 ControllerClassNameHandlerMapping 方法。

ControllerClassNameHandlerMapping 采用类名,如果存在则删除“控制器”后缀并返回剩余的文本,小写并带有前导“/”。

对于 LoginController,URL 路径映射将解析为“/login*”。

pathPrefix 指定要添加到从控制器名称生成的路径前面的前缀。

因此,当您在 ControllerClassNameHandlerMapping 中将 pathPrefix 指定为“/WEB-INF/flows/”时,对于 LoginController - URL 路径映射将解析为“/WEB-INF/flows/login*”。 您还有 FlowController,其 URL 路径映射将解析为“/WEB-INF/flows/flow*”。

这些都不匹配您调用的网址:localhost:8080/salonbooks/login

将您的 pathPrefix 更改为“/flows”。并尝试 localhost:8080/salonbooks/flows/login/login 调用 LoginController 中的 showLogin 方法。

【讨论】:

  • 我试图删除 controllerClassNameHandlerMapping() 和 LoginController 。登录页面显示但没有触发转换,错误与 BindingResult 和 bean 名称“命令”的普通目标对象都没有......想要 Spring WebFlow 管理这个,但 Spring Web Flow 没有管理它。看起来它正在通过 addViewControllers 方法映射到 ParameterizableViewController 。当我按照您的建议对其进行修改时,尝试使用 url localhost:8080/salonbooks/login 时仍然出现 BindingResult 错误
  • 显示你的流 xml 和 jsp。
  • 对于要调用的flowController,指定一个映射到flowcontroller的simpleurlhandlermapping。
  • 指定 并尝试。
  • 通过更改更新了故事,但现在我只看到严格的文本,而不是将 jsp 呈现为 html
【解决方案2】:

之前:

<servlet-mapping>
    <servlet-name>salonbooks</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

之后:

<servlet-mapping>
    <servlet-name>salonbooks</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

【讨论】:

    猜你喜欢
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 2016-02-09
    • 2014-01-31
    • 2017-05-05
    • 2016-02-13
    • 2018-02-18
    • 1970-01-01
    相关资源
    最近更新 更多