Introspection: Who am I? where am I? What am I going to do?
post @ 2019-10-13

想要写一篇介绍SockJS的文章,又不知道写什么好,发现官方github项目上这篇文章比较好,于是直接翻译过来。不长不短,正好合适。
该文章发布于2016年,某些论述可能已经过时,这里尝试加以纠正,但有谬误,还请指正。

阅读此文
post @ 2019-10-13

我是前端菜鸟,并不知道这三个是啥玩意儿,只是查查资料,让自己稍微了解一些。顺便说,这篇文章都是从别的地方抄来的。

阅读此文
post @ 2019-09-25

akka这个技术一致都在听人弹起,只知道它与后端有关,是一个牛B的框架,别的么。。。并不知道。那么,我觉得现在是时候了解一下了。

阅读此文

基于用户行为的理由

让用户直接说不就好了吗

本文标题是利用用户的数据行为, 是根据用户的实际动作进行演算的方法, 那为什么不利用用户语言进行演算呢? 最大的原因就是用户也说不清楚自己到底喜欢什么, 而用户的实际行为往往能够暴露其真实想法, 有些想法用户自己可能都还没有意识到.

阅读此文
post @ 2019-09-08

什么是推荐系统

推荐系统让用户能够发现对自己有价值的信息,另一方面,能够让信息展现在对它感兴趣的用户面前。实现消费者和生产者的双赢。

阅读此文
post @ 2019-09-08

Observable

ReactiveX中, 应用的是观察者模式, 一个观察者订阅一个被观察者. 然后该观察者根据被观察者释放的任何信息进行反应. 这样能够使得并发称为可能, 观察者不必阻塞等待被观察者的响应内容, 而是创建一个哨兵, 并随时准备在未来的任何时候响应被观察者释放出的内容

阅读此文
post @ 2019-09-07

这是一篇半翻译半笔记式的文章,如果你之前对Common FileUpload了解不多,本文可以快速了解如何使用方法,如果你有时间,推荐你看官方文档

阅读此文

自从入职新公司,在印象中应该是一直没有打开过自己的CSDN主页,甚至完全忘记了自己还有一个博客这件事。
今天偶然间看到一篇博文,说的是搭建一个自己的博客。想着自己也一直有着这样的想法,于是回来看了看。并想着:我得重新开始写博客

阅读此文
post @ 2018-10-15

Http全称?

超文本传输协议:Hypertext Transfer protocol
阅读此文
post @ 2018-09-09

基础

指定view-state的view属性的几种方式

  • 按照默认名称在相对路径下查找view
阅读此文
post @ 2018-09-08
  1. 文章中内容并没有全部验证,仅作为参考
  2. 上下文一起看,才能明白其中的意思

Web Flow中EL表达式作用

web-flow使用EL表达式访问flow的model和调用方法。在web-flow中EL表达式主要有如下四种用途

阅读此文
post @ 2018-09-08

action-state

简单使用

该状态只执行操作,然后根据操作的结果转移到其他state。可以有多个操作,他们依次执行

1
2
3
4
5
6
<!-- more -->
<action-state id="moreAnswersNeeded">
<evaluate expression="interview.moreAnswersNeeded()" />
<transition on="yes" to="answerQuestions" />
<transition on="no" to="finish" />
</action-state>

输出

在action-state中调用普通java对象的方法,这些方法返回的只是一般的值,但是transition标签需要Event来触发,因此web-flow会将这个普通返回值转换为Event对象,具体转换情况如下:

1
2
3
4
5
方法返回值类型			映射出来的EventId
java.lang.String 直接以字符串的值作为id
java.lang.Boolean yes (for true), no (for false)
java.lang.Enum the Enum name
any other type success

action-state的操作

action-state可以有三种方式进行执行操作

  • 调用POJO
1
<evaluate expression="pojoAction.method(flowRequestContext)" />
1
2
3
4
5
public class PojoAction {
public String method(RequestContext context) {
...
}
}
  • 实现Action接口,直接调用该action
1
<evaluate expression="customAction" />
1
2
3
4
5
public class CustomAction implements Action {
public Event execute(RequestContext context) {
...
}
}
  • 实现MultiAction接口,可以定义多个一连串的方法
1
<evaluate expression="multiAction.actionMethod1" />
1
2
3
4
5
6
7
8
9
10
public class CustomMultiAction extends MultiAction {
public Event actionMethod1(RequestContext context) {
...
}

public Event actionMethod2(RequestContext context) {
...
}
...
}

action的异常处理

  • POJO类action的处理方式
    发生异常时,返回相应的字符串,会映射成Event,在transition中响应就可以了,和普通方法正常返回一样
  • MultiAction的处理方式
    发生异常时,返回Event对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BookingAction extends MultiAction {
public Event makeBooking(RequestContext context) {
try {
Booking booking = (Booking) context.getFlowScope().get("booking");
BookingConfirmation confirmation = bookingService.make(booking);
context.getFlowScope().put("confirmation", confirmation);
return success();
} catch (RoomNotAvailableException e) {
context.getMessageContext().addMessage(new MessageBuilder().error().
.defaultText("No room is available at this hotel").build());
return error();
}
}
}
  • 使用exception-handler属性,定义异常处理器

decision-state

decision-state是action-state的一种简单替代,在if/else情况时比较好用

1
2
3
<decision-state id="moreAnswersNeeded">
<if test="interview.moreAnswersNeeded()" then="answerQuestions" else="finish" />
</decision-state>

action相关标签

1) <on-start> flow开始时执行
2) <on-entry> state进入时执行
3) <on-exit> state退出时执行
4) <on-end> flow结束时执行
5) <on-render>view-state中使用,渲染前执行
6) <transition> 在转移前执行

命名的action

如下展示了一个action-state下多个操作执行,为每个操作命名,第二个操作成功后进行转移操作

1
2
3
4
5
6
7
8
9
<action-state id="doTwoThings">
<evaluate expression="service.thingOne()">
<attribute name="name" value="thingOne" />
</evaluate>
<evaluate expression="service.thingTwo()">
<attribute name="name" value="thingTwo" />
</evaluate>
<transition on="thingTwo.success" to="showResults" />
</action-state>

向客户端发送流信息

应用场景

客户端请求一个图片文件,此时我们需要直接操作httpresponse进行图片的响应,而不是渲染view。

解决方案

通过ExternalContext获取HttpResponse,将图片写入,然后操作ExternalContext对象记录response完成,这样web-flow就不会再渲染view,而是直接返回给浏览器

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PrintBoardingPassAction extends AbstractAction {

@Override
protected Event doExecute(RequestContext context) throws Exception {
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getNativeResponse();
OutputStream os = response.getOutputStream();
// 在这里操作os,写入流数据
os.close();
context.getExternalContext().recordResponseComplete();
return success();
}

}
阅读此文
post @ 2018-09-07

基础

Web Flow将一个流程分为若干个状态(可以理解为步骤),每个流程由若干个状态组成,通过特性的方式在步骤之间进行跳转,协同完成整个流程。

阅读此文
post @ 2018-09-06

在学习每一门新语言时,第一个程序往往是Hello World。这里我们写一个非常简单的flow,使用常用标签,在深入讲解之前有一个感官上的认识

需求说明

假设有如下简单流程:要求程序启动,显式输入界面,用户输入信息后,点击提交按钮,后台查询数据库,然后显式查询结果界面,中间任何步骤出错,都重新返回输入界面,并显示错误信息。流程大体如下。

阅读此文
post @ 2018-09-05
  1. 本文基于Spring Web Flow 2.4.5,其它版本配置方式可能略有不同,请参考相应版本的官方文档
  2. Maven依赖
    maven库查询推荐地址:http://mvnrepository.com/
1
2
3
4
5
6
<dependency>
<!-- more -->
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.4.5.RELEASE</version>
</dependency>

Web Flow嵌入到Spring MVC工作流简介

请求被DispatcherServlet拦截 -> 分发flow进行处理,返回view -> viewResolver解析 -> 返回请求


配置项预览

  • FlowRegistry:必须,注册流程,指明流程配置文件所在位置;指定流程id(用于请求访问标识);指定流程属性;此外还可以传入FlowBuilderServices进行更多个性化配置
  • FlowBuilderServices:必须,用于设定流程配置文件中EL表达式的解析器、form属性绑定时的转换器、view-state的view解析器等,很重要
  • FlowExecutor:必须,用于执行流程,可指定执行监听器(可选,常用于流程安全和持久化)
  • FlowHandlerAdapter:必须,用于适配Spring MVC,配置时传入FlowExecutor
  • FlowHandlerMapping:必须,用于将请求映射到对应的flow,配置时传入FlowRegistry

配置I - 注册流程 - FlowRegistry

FlowRegistry用于注册流程实例,指定流程位置和流程id,并可自定义流程创建相关内容

注册flow的各种方式

  • 直接指定流程位置
    默认情况下,web-flow的id为其文件名减去后缀名,如下配置的id为booking。指定了基地址或使用了通配符时除外。

    1
    2
    <webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
    // 注册了一个路径为/WEB-INF/flows/booking/booking.xml的流程,其余为默认配置。
  • 自定义id

1
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" id="bookHotel" />
  • 定义流程属性
    如下定义了一个带有属性caption,其值为”Books a hotel”的流程。属性的使用方法暂时不了解

    1
    2
    3
    4
    5
    <webflow:flow-location path="/WEB-INF/flows/booking/booking.xml">
    <webflow:flow-definition-attributes>
    <webflow:attribute name="caption" value="Books a hotel" />
    </webflow:flow-definition-attributes>
    </webflow:flow-location>
    • 使用通配定义流程位置

使用该方法并没有正确实验出id,这点作为参考

1
<webflow:flow-location-pattern value="/WEB-INF/flows/**/*-flow.xml" />
  • 使用基地址
    使用基地址的flow的id为其path属性减去文件名,如下配置的id为/hotels/booking;如果path中没有路径信息,只有文件名,则id为文件名减去后缀。
    1
    2
    3
    <webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
    <webflow:flow-location path="/hotels/booking/booking.xml" />
    </webflow:flow-registry>

flow id属性总结

  1. id的作用
    id用于请求定位到某个确切的flow,如当请求路径为http://localhost:8090/Floyd/search-flow,其中Floyd是项目名,如果有id为search-flow的flow存在,则会访问该flow
  2. id的定义
    • 没有基地址或通配符时,flow的id为文件名减去后缀,如<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />这里的id为booking
    • 有基地址时,id为path的值减去文件名,如基地址为/WEB-INF, path=/flows/booking/booking.xml时,id被确定为flows/booking
    • 有通配符时,该情况比较特殊,按照官方说明并没有验证通过,这里略过。
      当显式指定了id属性时,则使用指定的id。推荐自定义id

      FlowRegistry继承

      FlowRegistry是可以继承的,可以定义一个公用的注册器,在多个子注册器中继承该注册器
1
2
3
4
5
6
7
8
9
<!-- my-system-config.xml -->
<webflow:flow-registry id="flowRegistry" parent="sharedFlowRegistry">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>

<!-- shared-config.xml -->
<webflow:flow-registry id="sharedFlowRegistry">
<!-- Global flows shared by several applications -->
</webflow:flow-registry>

配置II - 使用FlowBuilder services

使用FlowBuilder Services可以在build流程时自定义服务,比如视图解析器、EL表达式解析器、类型格式化和转换服务等。如无显式设定FlowBuilder Services,系统将使用默认实现。

1
2
3
4
5
6
7
8
9
10
11
12
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>

<webflow:flow-builder-services id="flowBuilderServices"
conversion-service="conversionService"
expression-parser="expressionParser"
view-factory-creator="viewFactoryCreator" />

<bean id="conversionService" class="..." />
<bean id="expressionParser" class="..." />
<bean id="viewFactoryCreator" class="..." />

自定义视图解析器 view-factory-creator

view-factory-creator用于视图解析工作,默认的creator可以支持Spring MVC支持的几种视图类型:JSP, Velocity,FreeMarker等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:location path="/WEB-INF/hotels/booking/booking.xml" />
</webflow:flow-registry>

<!-- 尤其注意这里的development,设置为true时表示开启开发模式,该模式下会在flow定义改变时自动re-load,甚至flow中引用的resource bundle发生了变化都会热重载 -->
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" development="true"/>

<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<!-- myExistingViewResolverToUseForFlows就是我们常用的视图解析器,注意这里引用的是一个列表 -->
<property name="viewResolvers" ref="myExistingViewResolverToUseForFlows"/>
</bean>

... ...
... ...
<!-- 做验证时使用的是javaconfig的形式,这种形式并没有验证过 -->
<property name="myExistingViewResolverToUseForFlows">
<list>
<ref bean="viewResolver" />
</list>
</property>

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>

自定义表达式解析器 expression-parser

expression-parser用于定义表达式解析器,默认的解析器使用逻辑:当类路径下有Unified EL解析器时,则使用;没有时,则使用OGNL表达式解析器(官方文档在EL表达式一章和系统设置一章关于默认表达式解析说法有出入,自己认为比较可信的是Spring Web Flow 2.1以后,默认使用Spring EL表达式解析器)。
下面是手动配置成Unified EL解析器的方式:

1
2
3
4
5
6
7
<webflow:flow-builder-services expression-parser="expressionParser"/>

<bean id="expressionParser" class="org.springframework.webflow.expression.el.WebFlowELExpressionParser">
<constructor-arg>
<bean class="org.jboss.el.ExpressionFactoryImpl" />
</constructor-arg>
</bean>

自定义类型转换器 conversion-service

详细内容参见本系列视图渲染相关章节或官方文档

1
2
3
4
5
6
7
8
9
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" ... />

<webflow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService" ... />

<bean id="defaultConversionService" class="org.springframework.binding.convert.service.DefaultConversionService">
<constructor-arg ref="applicationConversionSevice"/>
</bean>

<bean id="applicationConversionService" class="somepackage.ApplicationConversionServiceFactoryBean">
1
2
3
4
5
6
public class ApplicationConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
@Override
protected void installFormatters(FormatterRegistry registry) {
// ...
}
}

配置III - 发布流程执行器 - FlowExecutor

FlowExecutor用于执行flow并管理flow执行过程,常见的自定义项有:设置监听器,监听流程执行过程并作出相应,如security监听器,用于监听并控制流程的访问权限;调整flow的部分持久化选项等。

  • 注册监听器
1
2
3
4
<!-- 这里是为特定的flow应用该监听器,当不设criteria属性时,将对所有flow应用 -->
<webflow:flow-execution-listeners>
<webflow:listener ref="securityListener" criteria="securedFlow1,securedFlow2"/>
</webflow:flow-execution-listeners>
  • 调整持久化参数
    • max-executions: 设定为每个用户保留的执行数(没错,就是执行数),当超过该数量时,最先的那个执行会被清除。(这里的执行,我认为是一个新开的且处于激活状态下的flow实例)
    • max-execution-snapshots: 设定每个执行保留的最大快照数。不允许保留时,设为0。允许无线保留时,设为-1。(快照用于浏览器的返回按钮)
      1
      2
      3
      <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
      <webflow:flow-execution-repository max-executions="5" max-execution-snapshots="30" />
      </webflow:flow-executor>

配置IV - Spring MVC集成

基础配置(将请求转发给flow)

  • Spring MVC基础配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-application-config.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<!-- 不能使用类型/*的通配符进行匹配,否则会出现jsp不解析直接回发给浏览器的情况 -->
<url-pattern>/</url-pattern>
</servlet-mapping>

FlowHandlerAdapter

该步骤是使得Web Flow能够适配Spring MVC
当一个对flow的请求被接收到时,FlowHandlerAdapter会决定是启动一个全新的flow还是继续之前的流程(如从一个view-state跳转到下一个state就属于继续之前的流程),继续之前的flow是需要在请求有相关信息才行。有关这一方面,web flow默认有如下设定:
  1.Http请求参数在任何情况下都是可以使用的
  2.当一个flow执行结束,且结束时没有想浏览器发送最后的响应时,默认的handler会尝试在同一个request中启动一个新的flow执行
  3.除了NoSuchFlowExecutionException异常外,所有其它异常都会以冒泡的方式抛到Dispatcher中。这是因为默认的handler会尝试自动从该异常中恢复过来,恢复的方式是新开一个全新的flow执行
针对大多数设定,都可以通过实现FlowHandlerAdapter类的子类进行自定义。

1
2
3
4
5
<!-- Enables FlowHandler URL mapping -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<!-- flowExecutor就是前文声明的执行器 -->
<property name="flowExecutor" ref="flowExecutor" />
</bean>

配置V - FlowHandlerMapping

1
2
3
4
5
6
7
<!-- Maps request paths to flows in the flowRegistry;
e.g. a path of /hotels/booking looks for a flow with id "hotels/booking" -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<!-- flowRegistry就是前文声明的注册器 -->
<property name="flowRegistry" ref="flowRegistry"/>
<property name="order" value="0"/>
</bean>

有了Flow的基本配置和这里的两个Spring MVC的集成配置,请求就能够映射到flow中了。接下来就是写Flow了。想要快速上手的可忽略本文后面的内容,转而直接看本系列其它文章。


配置VI - 实现自定义的FlowHandler

  • FlowHandler讲解
    FlowHandler可用于自定义flow在HTTP Servlert环境中执行的方式,FlowHandler在FlowHandlerAdapter中被使用,主要负责如下内容:

      - 返回flow的id以用于执行该flow
      - 在新流程开始时创建输入
      - 在流程结束时处理流程的输出
      - 在流程发生异常时,处理这些异常

    其主要方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
public interface FlowHandler {

public String getFlowId();

public MutableAttributeMap createExecutionInputMap(HttpServletRequest request);

public String handleExecutionOutcome(FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response);

public String handleException(FlowException e,
HttpServletRequest request, HttpServletResponse response);
}

  该接口的直接实现为AbstractFlowHandler,当我们想要自定义某个设定时,继承该抽象类并重写其中的方法即可。

  • 发布一个FlowHandler
    一个FlowHandler负责一个flow,发布方式是在Spring环境中声明一个bean,该bean的name必须和我们想要处理的flow的id一致,配置好后,当方位该flow的id,则会定位到新发布的FlowHandler中,我们自定义的方法也就生效了。
1
2
<!-- 这里的BookingHandler只是一个例子,实际用时替换成我们自己的Handler -->
<bean name="hotels/booking" class="org.springframework.webflow.samples.booking.BookingFlowHandler" />
  • 着重讲一下FlowHandler中handleExecutionOutcome(…)方法
    该方法用于处理flow结束时产生的FlowExecutionOutcome(系统自动产生),我们常用它来在流程结束后进行重定向,比如
1
2
3
4
5
6
7
8
9
10
11
12
public class BookingFlowHandler extends AbstractFlowHandler {
// handlExecutionOutcome()方法返回的String代表的是重定向的地址
public String handleExecutionOutcome(FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response) {
if (outcome.getId().equals("bookingConfirmed")) {
return "/booking/show";
} else {
return "/hotels/index";
}
}
}
// 当flow id为bookinConfirmed时,重定向到/booking/show,否则重定向到/hotels/index

  默认情况下,该方法返回的地址是相关于当前Servlet的。但是我们也可以显式地指定一些前缀来扩展重定向的范围

   – servletRelative: - 相对于当前Servlet重定向
   – contextRelative: - 相对于当前应用重定向
   – serverRelative: - 相对于当前服务器的基地址重定向
   – http:// or https:// - 重定向到一个完整的URI地址

  相同的前缀同样适用于声明state时的view属性配上externalRedirect的情况

1
2
<end-state view="externalRedirect:http://springframework.org"/>
<!-- 在流程结束时,跳转到spring首页 -->

—————————————————–手动分割线——————————————————————————————

一个能用的配置(采用Java config的方式配置)

WebInitializer(与web.xml作用类似)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {MainConfig.class, RegisterConfig.class};
}

@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}

}

MainConfig(Spring的主要配置文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Configuration
@EnableWebMvc
@ComponentScan("cn.floyd.pw")
public class MainConfig extends WebMvcConfigurerAdapter{

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

@Bean
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
return resolver;
}

// enable the static resource
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

@Bean
public FlowHandlerAdapter flowHandlerAdapter(@Autowired FlowExecutor flowExecutor) {
System.out.println("init flowHandlerAdapter");
FlowHandlerAdapter adapter = new FlowHandlerAdapter();
adapter.setFlowExecutor(flowExecutor);

return adapter;
}

@Bean
public FlowHandlerMapping flowHandlerMapping(@Autowired FlowDefinitionRegistry flowRegistry) {
System.out.println("init flowHandlerMapping");
FlowHandlerMapping mapping = new FlowHandlerMapping();
mapping.setOrder(0);
mapping.setFlowRegistry(flowRegistry);

return mapping;
}

}

RegisterConfig(配置FlowRegister和flowExecutor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Configuration
public class RegisterConfig extends AbstractFlowConfiguration {

// 用于注册flow
@Bean("flowRegistry")
public FlowDefinitionRegistry flowRegistry(@Autowired FlowBuilderServices flowBuilderServices) {

return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF/jsp/flow")
.addFlowLocation("/config/search-flow.xml")
.setFlowBuilderServices(flowBuilderServices)
.build();
}

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

@Bean
public MvcViewFactoryCreator mvcViewFactoryCreator(@Autowired ViewResolver viewResolver) {
MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
List<ViewResolver> list = new ArrayList<ViewResolver>();
list.add(viewResolver);
creator.setViewResolvers(list);

return creator;
}

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

}

配置时踩过的坑

flow id的坑

最开始对flow id的认识不够,导致不知道到底该如何定位到flow,其实访问方式就是 …/appName/flowId

Web MVC Environment null not supported

启动时正常,访问flow时报异常java.lang.IllegalStateException: Web MVC Environment null not supported
是在创建viewFactory时出错,由于我没有采用在config中声明bean的方式创建MvcViewFactoryCreator,因此出现找不到mvc环境的问题,原来是spring在自动检测并创建bean时,会同时设置该bean的环境,因此不能自己随意采用new的方式创建这些配置类

JSP文件不解析

出现JSP文件不经过解析就直接传送给了浏览器的问题(对如下阐述的原理并不是很清楚)
url-pattern为”/*”时,能够匹配到任何路径,因此当controller返回.jsp文件时,也会被拦截,从而返回jsp源码(这里不是很理解,主要是跟自己认识的spring mvc处理流程有差别)。
url-pattern为”/“时,只能够匹配不带后缀的路径,因此jsp就不会被dispatcherServlet拦截,而是会被jspServlet拦截并处理。但是”/“在配置使能的情况下也能够拦截并允许静态资源的访问

阅读此文
⬆︎TOP