2014-11-27 2 views
0

У меня есть поток, который, казалось, работал нормально до вчерашнего дня, когда внезапно я начал получать следующее исключение на моей странице HTML, которая отображается в первом состоянии в моем потоке:Spring WebFlow (по-видимому) случайно перестает работать в Spring Boot app

org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'flowScope' cannot be found on null 

нарушитель строка кода была:

<h3 th:text="${flowRequestContext.flowScope}"/> 

Дальнейшие исследования показали, что ни одна из переменных потока не доступны больше. Более того, если я поставлю операторы печати в службу, к которой поток обращается к различным вызовам, я вижу, что ни один из этих методов больше не вызывается - это похоже на то, что поток просто не работает.

Этот был, работая нормально ранее. Я даже вернул все мои локальные изменения в ранее стабильную версию кода, и эта же проблема также происходила там. Единственная вещь, которая, казалось, временно обошла эту проблему, заключалась в том, чтобы перезагрузить компьютер - проблема исчезла ненадолго, а затем вернулась.

Чтобы быть честным, я полностью не в курсе, что могло начаться, вызвав такую ​​прерывистую проблему. Я думал о том, что старый процесс Java работает в фоновом режиме, мешая будущим запускам приложения, но проверил и уничтожил любой оставшийся процесс между развертываниями безрезультатно.

Я включил, что я надеюсь, соответствующий файл ниже. Любая помощь в решении этой проблемы будет очень оценена.

checkout.xml

<?xml version="1.0" encoding="UTF-8"?> 
<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"> 

    <on-start> 
     <set name="flowScope.paymentMethods" value="checkoutWidgetService.getPaymentMethods()"/> 
     <set name="flowScope.deliveryAddress" value="checkoutWidgetService.getDeliveryAddress()"/> 
     <set name="flowScope.sessionId" value="externalContext.nativeRequest.session.id"/> 
    </on-start> 

    <view-state id="payment-methods" view="payment-methods"> 
     <transition on="selectPaymentMethod" to="new-details"> 
      <evaluate expression="checkoutWidgetService.getCardDetails(requestParameters.type)" result="flowScope.cardDetails"/> 
     </transition> 
    </view-state> 

    <view-state id="new-details" view="new-details"> 
     <transition on="submitDetails" to="summary"> 
      <evaluate expression="checkoutWidgetService.buildCardDetails(requestParameters)" result="flowScope.cardDetails"/> 
     </transition> 
    </view-state> 

    <view-state id="summary" view="summary"> 
     <transition on="completeCheckout" to="redirect"> 
      <evaluate expression="checkoutWidgetService.completeCheckout(externalContext.nativeRequest.session, flowRequestContext, flowScope.cardDetails)"/> 
     </transition> 
     <transition on="cancelCheckout" to="redirect"> 
      <evaluate expression="checkoutWidgetService.cancelCheckout(externalContext.nativeRequest.session, flowRequestContext)"/> 
     </transition> 
    </view-state> 

    <end-state id="redirect" view="externalRedirect:contextRelative:/payments/checkout-widgets/end"/> 
</flow> 

WebflowConfig.java

@Configuration 
@AutoConfigureAfter(MvcConfig.class) 
public class WebflowConfig extends AbstractFlowConfiguration { 

    @Autowired 
    private SpringTemplateEngine templateEngine; 

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

    @Bean 
    public FlowDefinitionRegistry flowRegistry() { 
     return getFlowDefinitionRegistryBuilder(flowBuilderServices()) 
       .addFlowLocation("classpath:/templates/checkout.xml", "payments/checkout-widget/start") 
       .build(); 
    } 

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

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

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

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

    @Bean 
    public AjaxThymeleafViewResolver thymeleafViewResolver() { 
     AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver(); 
     viewResolver.setViewClass(FlowAjaxThymeleafView.class); 
     viewResolver.setTemplateEngine(templateEngine); 
     return viewResolver; 
    } 

    @Bean 
    public MvcViewFactoryCreator mvcViewFactoryCreator() { 
     List<ViewResolver> viewResolvers = new ArrayList<>(); 
     viewResolvers.add(thymeleafViewResolver()); 

     MvcViewFactoryCreator mvcViewFactoryCreator = new MvcViewFactoryCreator(); 
     mvcViewFactoryCreator.setViewResolvers(viewResolvers); 
     mvcViewFactoryCreator.setUseSpringBeanBinding(true); 
     return mvcViewFactoryCreator; 
    } 

} 

CheckoutWidgetSessionMvcController.java

@Controller 
@RequestMapping("/payments/checkout-widgets") 
public class CheckoutWidgetSessionMvcController { 

    @Inject 
    private CheckoutWidgetService service; 

    @RequestMapping(value = {"/start"}, method = RequestMethod.GET) 
    public ModelAndView paymentMethods() { 
     return new ModelAndView("payment-methods", null); 
    } 

    @RequestMapping(value = "/end", method = RequestMethod.GET) 
    public String invalidateSession(HttpSession session) { 
     service.invalidateSession(session); 
     return "dummy-redirect-post"; 
    } 
} 

CheckoutWidgetService.java

public interface CheckoutWidgetService { 

    List<PaymentMethod> getPaymentMethods(); 

    CardDetails getCardDetails(String name); 

    CardDetails buildCardDetails(LocalParameterMap params); 

    String getDeliveryAddress(); 

    void completeCheckout(HttpSession session, RequestContext context, CardDetails cardDetails); 

    void cancelCheckout(HttpSession session, RequestContext context); 

    void invalidateSession(HttpSession session); 
} 

CheckoutWidgetServiceImpl.java

@Service("checkoutWidgetService") 
public class CheckoutWidgetServiceImpl implements CheckoutWidgetService { 

    @Inject 
    private CheckoutWidgetSessionService sessionService; 

    private final List<PaymentMethod> paymentMethods = new ArrayList<>(); 

    private final String deliveryAddress; 

    public CheckoutWidgetServiceImpl() { 
     paymentMethods.add(new PaymentMethod("PayPal", "/images/paypal-logo.png")); 
     paymentMethods.add(new PaymentMethod("Mastercard", "/images/mc-logo.png")); 
     paymentMethods.add(new PaymentMethod("Visa", "/images/visa-logo.png")); 
     paymentMethods.add(new PaymentMethod("Amex", "/images/amex-logo.png")); 
     paymentMethods.add(new PaymentMethod("Google Checkout", "/images/google-logo.png")); 
     deliveryAddress = "xxxxx"; 
    } 
    @Override 
    public List<PaymentMethod> getPaymentMethods() { 
     System.out.println("Returning paymentMethods: " + paymentMethods); 
     return paymentMethods; 
    } 

    @Override 
    public CardDetails getCardDetails(String name) { 
     CardDetails cardDetails = new CardDetails(); 
     cardDetails.setCardType(name); 
     return cardDetails; 
    } 

    @Override 
    public CardDetails buildCardDetails(LocalParameterMap params) { 
     CardDetails cardDetails = new CardDetails(); 
     cardDetails.setCardNumber(params.get("cardNumber")); 
     cardDetails.setExpiryMonth(params.get("expiryMonth")); 
     cardDetails.setExpiryYear(params.get("expiryYear")); 
     cardDetails.setNameOnCard(params.get("nameOnCard")); 
     cardDetails.setCvv2(params.get("cvv2")); 
     return cardDetails; 
    } 

    @Override 
    public String getDeliveryAddress() { 
     return deliveryAddress; 
    } 

    @Override 
    public void invalidateSession(HttpSession session) { 
     session.invalidate(); 
    } 

    private RedirectUrls getRedirectUrls(String sessionId) { 
     CheckoutWidgetSession widgetSession = sessionService.getCheckoutWidgetSession(sessionId).get(); 
     return widgetSession.getRedirectUrls(); 
    } 

    @Override 
    public void completeCheckout(HttpSession session, RequestContext context, CardDetails cardDetails) { 
     RedirectUrls redirects = getRedirectUrls(session.getId()); 

     context.getFlowScope().remove("paymentMethods"); 

     UriBuilder uriBuilder = UriBuilder.fromUri(URI.create(redirects.getSuccessUrl())); 
     String forwardUrl = uriBuilder.queryParam("transactionId", "12345").toString(); 
     context.getFlowScope().put("forwardUrl", forwardUrl); 
     context.getFlowScope().put("target", "_top"); 
    } 

    @Override 
    public void cancelCheckout(HttpSession session, RequestContext context) { 
     RedirectUrls redirects = getRedirectUrls(session.getId()); 

     context.getFlowScope().remove("paymentMethods"); 

     String forwardUrl = redirects.getCancelUrl(); 
     context.getFlowScope().put("forwardUrl", forwardUrl); 
     context.getFlowScope().put("target", "_top"); 
    } 
} 

Применение.Java

@EnableAutoConfiguration 
@ComponentScan(basePackages = {"com.pay.widgets.checkout"}) 
@Import(JerseyAutoConfiguration.class) 
public class Application extends SpringBootServletInitializer { 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     return application.sources(Application.class); 
    } 

    public static void main(String[] args) { 
     SpringApplication.run(Application.class, args); 

    } 
} 

ответ

0

Хорошо это было действительно глупая ошибка с моей стороны, проблема оказалась вниз к опечатке в @RequestParameter аннотацию на контроллере:

payments/checkout-widgets 

Который не сделал выстраиваться с тем, что было в WebflowConfig определено flowRegistry:

payments/checkout-widget 

Я только можно предположить, что ресурс был кэшируются Tomcat, который почему потребовалось так много времени для выпуска на ма и отбросил меня от запаха с точки зрения подозрения в моих собственных изменениях, которые несут ответственность.