Struts2核心流程图
1. Struts2 和 Struts1 对比
struts1:基于Servlet(ActionServlet),actionForm众多(类的爆炸),action单例(数据安全[线程安全]问题).
将所有任务的解决都集于一身.(不容易扩展和定制)
action位于控制层. extends Action{...}
action更struts1的action和原生servlet api(HttpServletRequest,HttpServlerResponse)绑定在一起,
因此不容易测试,需要部署到web容器中进行测试.
回显数据:struts-html.tld <html:checkbox> html:text
struts-bean.tld
struts-logic.tld
//
class CustomerAction extends DispatchAction{
public ActionForward save(ActionMapping ActionForm Request,Response){
}
public ActionForward update(ActionMapping ActionForm Request,Response){
}
}
<action-mappings>
<action path="/customerAction"
name="customerForm"
scope="request|session"
validate="true"
input="/xxx.jsp"
type="xxxx..CustomerAction"
parameter="method" />
http://xxx/sss/customerAction.do?method=save
struts2:基于filter,没有actionform,action(原型的,独占).
seperate aware:分离关注.解耦.(interceptor,拦截器).
action是模型层(接受参数+pojo).
action不需要和struts的action和原生servlet API(HttpServletRequest,HttpServlerResponse)耦合在一起.
所以更容易测试,不需要一定要部署到web环境中进行测试.
struts2是更加整洁的mvc框架(原因是采用了seperate aware技术,实现任务的拆解).
体验struts2:
1.创建web项目
2.引入struts2类库
${struts解压目录}/app/struts2-blank-2.1.8.1.war/web-inf/lib/*.jar
3.创建action.
package cn.itcast.struts2.action;
/**
* HelloWorldAction
*/
public class HelloWorldAction {
public String execute(){
System.out.println("hello world");
return null ;
}
}
4.创建struts配置文件.src/struts.xml
dtd:struts-core.jar/struts-2.1.7.dtd/30行
<?xml version="1.0"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<package name="HelloWorldPkg" namespace="/helloworld">
<action name="HelloWorldAction" class="cn.itcast.struts2.action.HelloWorldAction" />
</package>
</struts>
5.配置struts2的过滤器web-inf/web.xml文件中
类:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>action</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>action</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
struts2包搜索顺序:
http://localhost:8085/lsn_struts2/helloworld/aaa/bbb/HelloWorldAction.action
http://localhost:8085/lsn_struts2/helloworld/aaa/bbb/
http://localhost:8085/lsn_struts2/helloworld/aaa/
http://localhost:8085/lsn_struts2/helloworld
list lst = .. ;
request.setAttribute("list",list); Map<String,Object>
request.getRequestDispatcher("/xxxx.jsp").forward(request,response);
HttpServletResponse.sendRedirect("/xx");
ContentType:
response.setContentType("text/html");
mime:
(HttpServletRequest)request.getAttribute("list");
request.setAttribute("list",list);
map:Sessoin (ServletContext)Application.setAttri
使用Token拦截器避免表单重复提交:
1.在jsp页面上使用<s:token />
2.在拦截器栈中加入token拦截器.
Google:
Web:异步执行.
2. 实例: 表单提交 ,校验,防重复提交,文件上传
web.xml 配置
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <filter> <filter-name>action</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>action</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
struts.xml配置 包含模块 reg.xml
<?xml version="1.0"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <!-- 通过常量方式改变struts默认的属性配置, --> <constant name="struts.action.extension" value="do" /> <!-- 设置开发模式,重新加载国际化资源文件和配置文件 --> <constant name="struts.devMode" value="true" /> <!-- 动态方法调用 --> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <package name="HelloWorldPkg" namespace="/helloworld" extends="struts-default"> <!-- 默认该包下默认的action引用,若该包没有要访问的action元素,则使用默认的action引用 --> <default-action-ref name="HelloWorldAction" /> <!-- 设置默认的class引用,将摸个类作为默认的action类 --> <default-class-ref class="cn.itcast.struts2.action.HelloWorldAction" /> <!-- 通过通配符的方式实现动态方法调用 --> <action name="HelloWorldAction_*" class="cn.itcast.struts2.action.HelloWorldAction" method="{1}"> <result name="success">/index.jsp</result> <result name="save">/index.jsp</result> <result name="update">/success.jsp</result> </action> <!-- 没有类的action --> <action name="ActionNoClass"> <result>/index.jsp</result> </action> </package> <!-- 模块话编程,包含配置文件 --> <include file="cn/itcast/struts2/action/reg.xml" /> </struts>
reg.xml 配置
<?xml version="1.0"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <package name="RegPkg" namespace="/regns" extends="struts-default"> <action name="RegAction_*" class="cn.itcast.struts2.action.RegAction" method="{1}"> <result name="success">/reg/success.jsp</result> <result name="error">/reg/error.jsp</result> <result name="regView">/reg/reg.jsp</result> <result name="input">/reg/reg.jsp</result> <interceptor-ref name="defaultStack"> <!--动态方法调用,方式之一--> <param name="validation.excludeMethods">input,back,cancel,toRegView</param> </interceptor-ref> </action> </package> </struts>
token.xml 防止重复提交 配置
<?xml version="1.0"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <package name="TokenPkg" namespace="/token" extends="struts-default"> <action name="TokenAction_*" class="cn.itcast.struts2.token.TokenAction" method="{1}"> <result name="success">/token/success.jsp</result> <result name="regView">/token/reg.jsp</result> <!--无效令牌--> <result name="invalid.token">/token/reg.jsp</result> <result name="wait">/wait.jsp</result> <!-- 如果指定了一个拦截器,则覆盖默认的配置,必须手动指定默认栈 --> <interceptor-ref name="token"> <param name="excludeMethods">toRegView,findAllCustomers</param> </interceptor-ref> <interceptor-ref name="defaultStack" /> <!-- 执行等待拦截器 --> <interceptor-ref name="execAndWait" /> </action> </package> </struts>
reg.jsp 表单提交 JSP, 使用struts-tags 标签,数据回显与校验
<%@ page language="java" contentType="text/html; charset=utf-8"%> <%@taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>reg.jsp</title> </head> <body> <s:debug /> <s:actionerror /> <s:form namespace="/regns" action="RegAction_reg" method="post" enctype="multipart/form-data"> <s:token /> <!--防止重复提交--> <s:textfield name="name" label="UserName" /> <s:textfield name="age" label="UserAge" /> <s:file name="photo" label="UserPhoto" /> <s:submit /> </s:form> </body> </html>
RegAction.java 处理action
public class RegAction extends ActionSupport { private static final long serialVersionUID = 2941355104469235318L; private String name; private Integer age; /* 接受上传的文件 */ private File photo ; /* 接受文件名称 */ private String photoFileName ; /* 接受文件内容类型的 */ private String photoContentType ; public String getPhotoFileName() { return photoFileName; } public void setPhotoFileName(String photoFileName) { this.photoFileName = photoFileName; } public String getPhotoContentType() { return photoContentType; } public void setPhotoContentType(String photoContentType) { this.photoContentType = photoContentType; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } /** * */ public String reg(){ System.out.println("reg : " + name); String dir = ServletActionContext.getServletContext().getRealPath("/upload"); String ext = photoFileName.substring(photoFileName.lastIndexOf(".")); long l = System.nanoTime(); File newFile = new File(dir,l + ext); photo.renameTo(newFile); return SUCCESS; } /** * 达到注册页面, 动态方法调用之一, 使用SkipValidation标签掉过校验 */ //@SkipValidation public String toRegView(){ return "regView" ; } /** * 动态方法调用之一,命名: validate + 要校验方法(Reg) == void validateReg() {} */ public void validate() { if(name == null || name.length() == 0){ //国际化,getText会从配置文件获得message,配置文件名和类名一致,位置相同,RegAction.properties addFieldError("name",getText("error.name.empty")); } } public File getPhoto() { return photo; } public void setPhoto(File photo) { this.photo = photo; } }
RegAction.properties 国际化配置文件
error.name.empty=name is required! error.name.age=age is required!
success.jsp 成功跳转JSP
<%@ page language="java" contentType="text/html; charset=utf-8"%> <%@taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>index.jsp</title> </head> <body> you input's name is <s:property value="name" />.<br> you input's age is <s:property value="age" />.<br> </body> </html>
wait.jsp 等待页面
<%@ page language="java" contentType="text/html; charset=utf-8"%> <%@taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>wait.jsp</title> <meta http-equiv="refresh" content="2;url=<s:url/>"/> </head> <body> 处理中,请稍后.... </body> </html>