1.方法修饰符不对出现的错误
com.alibaba.citrus.service.pipeline.PipelineException
Failed to invoke Valve[#2/3, level 3]: com.alibaba.citrus.turbine.pipeline.valve.PerformTemplateScreenValve#a28815:PerformTemplateScreenValve
caused by com.alibaba.citrus.service.mappingrule.MappingRuleException
com.alibaba.citrus.service.moduleloader.UnadaptableModuleException: Could not adapt object to module: type=screen, name=ViewUser, class=class com.alibaba.webx.tutorial1.register.module.screen.ViewUser
caused by com.alibaba.citrus.service.moduleloader.UnadaptableModuleException
Could not adapt object to module: type=screen, name=ViewUser, class=class com.alibaba.webx.tutorial1.register.module.screen.ViewUser
- 首先检查配置是否错误;
- 当配置没有错误时,可考虑出现在ViewUser程序里所要调用的方法是否是public方法,本例中即ViewUser里的excute方法。因为方法若为私有或者保护类型则会无法调用。
2.重定向时出现的问题
Exception Occurred
com.alibaba.citrus.service.pipeline.PipelineException
Failed to invoke Valve[#2/3, level 3]: com.alibaba.citrus.turbine.pipeline.valve.PerformTemplateScreenValve#287ca7:PerformTemplateScreenValve
caused by com.alibaba.citrus.webx.WebxException
Failed to execute screen: ViewUser
caused by java.lang.NullPointerException
No Message
- 空值问题可能是外部重定向时,context无法共享造成的。
3.运行.do时出现的错误
Exception Occurred
com.alibaba.citrus.service.pipeline.PipelineException
Failed to invoke Valve[#2/2, level 3]: com.alibaba.citrus.turbine.pipeline.valve.PerformScreenValve#2c390c:PerformScreenValve
caused by com.alibaba.citrus.webx.WebxException
Failed to load screen module: Register
caused by com.alibaba.citrus.service.moduleloader.ModuleNotFoundException
Could not find screen module: Register
- 在管道设置不变的情况下,.do运行时可以没有action类,但一定要有screen类(若只有action类,在执行action类的时候进行重定向的情况除外),否则出现上述错误。
- 当没有action参数的时候,会跳过action,直接运行screen类;
- 管道流程:根据action参数 先找action类,然后screen类, 最后渲染screen模板等。 若没有screen类也没有设定action参数,则作为静态 直接找模板;
- 渲染layout模板的时候,control类直接在layout模板里调用,然后再渲染control模板:
支持模板 | $control.setTemplate("myControl.vm") |
无模板 | $control.setModule("myControl") |
- 管道设置如下:
<loop> <choose> <when> <!-- 执行带模板的screen,默认有layout。 --> <pl-conditions:target-extension-condition extension="null, vm, jsp" /> <performAction /> <performTemplateScreen /> <renderTemplate /> </when> <when> <!-- 执行不带模板的screen,默认无layout。 --> <pl-conditions:target-extension-condition extension="do" /> <performAction /> <performScreen /> </when> <otherwise> <!-- 将控制交还给servlet engine。 --> <exit /> </otherwise> </choose> <!-- 假如rundata.setRedirectTarget()内部重定向,被设置,则循环,否则退出循环。 --> <breakUnlessTargetRedirected /> </loop>
4.web应用根路径问题
<img src="$workshopContent.setContentPath("images/logo_webx.png")"/>
- 这个images文件夹处于webapp下,原因如下:
public static void main(String[] args) throws Exception {
Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(80);
server.addConnector(connector);
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setDescriptor("src/main/webapp/WEB-INF/web.xml");
context.setResourceBase("src/main/webapp");//这里设置了基本路径
server.setHandler(context);
server.start();
}
5.前台页面的跳转链接
οnclick="location='$workshopModule.setTarget("modifyUser.vm").addQueryData("id", $user.id)'"/>
6.form的问题
- 从form中取得group:
每个form都可以包含一个或多个group。Group被定义在form.xml中。每个group都有一个唯一的名字。我们必须取得名为“register”的group,才能取得用户填写的数据。 - 在group设置error字段后,在程序里往其里面设置信息的时候代码如下:
Map params = ArrayUtil.toMap(new String[][] {
{ "id", userId }
});
group.getField("error").setMessage("wrongIdOrPassword", params);
7.pull服务的应用
-
Pull服务的设置:请注意,UserAuth对象应该是global作用域的 —— 因为它的所有方法都是static的,没有必要在每个请求中都创建该对象。这样,模板就可以访问$userAuth对象了。
- 配置如下
<services:pull xmlns="http://www.alibaba.com/schema/services/pull/factories">
<utils />
<rundata-tool />
<csrfToken />
<form-tool />
<control-tool />
<uris-tool />
<pull-factories:bean-tool id="userAuth" scope="global"
class="com.alibaba.webx.tutorial1.util.UserAuth"/>
</services:pull>
- UserAuth.java
package com.alibaba.webx.tutorial1.util;
import com.alibaba.webx.tutorial1.register.SiteUser;
public class UserAuth {
private static final ThreadLocal<SiteUser> userHolder = new ThreadLocal<SiteUser>();
public static void setLoginUser(SiteUser user) {
userHolder.set(user);
}
public static SiteUser getLoginUser() {
return (SiteUser) userHolder.get();
}
public static boolean isLoggedIn() {
return getLoginUser() != null;
}
}
- UserAuthVale.java
package com.alibaba.webx.tutorial1.util;
import static com.alibaba.citrus.turbine.util.TurbineUtil.getTurbineRunData;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.citrus.service.pipeline.PipelineContext;
import com.alibaba.citrus.service.pipeline.support.AbstractValve;
import com.alibaba.citrus.turbine.TurbineRunData;
import com.alibaba.webx.tutorial1.register.SiteUser;
public class UserAuthValve extends AbstractValve {
@Autowired
private HttpServletRequest request;
private String action;
public void setAction(String action) {
this.action = action;
}
public void invoke(PipelineContext pipelineContext)
throws Exception {
TurbineRunData rundata = getTurbineRunData(request);
if (!"cleanup".equals(action)) {
SiteUser user = (SiteUser) rundata.getRequest().getAttribute("loginUser");
if (user != null) {
UserAuth.setLoginUser(user);
System.out.print("设置了user");
}
} else {
UserAuth.setLoginUser(null);
System.out.print("user为空");
}
pipelineContext.invokeNext();
}
}
- 这里采用ThreadLocal解决非线程安全问题;
- 在模板里调用如下:
#if ($userAuth.loggedIn)
<p>你好,$userAuth.loginUser.name</p>
#else
<p>你好,世界!</p>
#end
8.webx里的多模块配置
<services:components > <services:component name="register" path="/register"></services:component> <services:component name="app1" path="/app1"></services:component> </services:components>
这样将就可以访问register模块了,url为:http://localhost:80/register/xxx.htm