Struts2相关知识整合
来源:互联网 发布:ipad 下载软件 编辑:程序博客网 时间:2024/05/16 07:27
网站
Apache Struts 2 http://struts.apache.org/2.x/index.html
Opensymphony XWork http://www.opensymphony.com/xwork
Opensymphony WebWork http://www.opensymphony.com/webwork
Struts2是使用Filter作为控制器
Struts2,Struts
Struts 2 = WebWork 2.2
对比:
1.配置文件:Struts1配置文件放在WEB-INF/struts-config.xml(可定制)目录下;Struts2的配置文件要放在WEB-INF/classes目录下
2.控制器:Struts1的控制器是一个ActionServlet类;Struts2的控制器是一个过滤器。
3.动作表单:Struts1的HTML表单对应一个ActionForm类的实例,动作类可访问对应配置的ActionForm,操作ActionForm进行填充数据传输对象;Struts2的HTML表单直接映射成POJO,动作类中可直接访问POJO,操作对POJO的验证。
4.动作类:Struts1的动作类继承org.apache.struts.action.Action类;Struts2的动作类可以是任何一个POJO,但是最好是继承ActionSupport类?。
5.显示对象:在JSP中Struts2使用OGNL来显示各种对象模型,JSP自带的JSTL和EL中EL常用来补充使用。
6.标签库:Struts1常用HTML标签库、Bean标签库和Logic标签库;Struts2有通用标签库、表单标签库? 。
为什么最好是继承ActionSupport类 ?Struts2的标签具体有哪些
Action 跟 Actionsupport 的区别
Action接口有:
public static final java.lang.String SUCCESS = "success";
public static final java.lang.String NONE = "none";
public static final java.lang.String ERROR = "error";
public static final java.lang.String INPUT = "input";
public static final java.lang.String LOGIN = "login";
public abstract java.lang.String execute() throws java.lang.Exception;
而Actionsupport这个工具类在实现了Action接口的基础上还定义了一个validate()方法,重写该方法,它会在execute()方法之前执行,如校验失败,会转入input处,必须在配置该Action时配置input属性。
另外,Actionsupport还提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息.
这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化。
2.8
为了避免用户的输入引起底层异常,通常我们会在进行业务逻辑操作之前,先执行基本的数据校验。
2.8.1
ActionSupport类是一个工具类,它已经实现了Action接口。除此之外,它还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2的Action开发。
在Validatable接口中定义了一个validate()方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类的fieldErrors域中,然后通过OGNL表达式负责输出。
为了让Struts 2增加输入数据校验的功能,改写程序中的LoginAction,增加重写validate方法。修改后的LoginAction类代码如下:
//Struts 2的Action类就是一个普通的Java类public class LoginAction{//下面是Action内用于封装用户请求参数的两个属性private String username;private String password;//username属性对应的getter方法 public String getUsername(){ return username; }//username属性对应的setter方法 public void setUsername(String username){ this.username = username;}//password属性对应的getter方法 public String getPassword(){ return password; }//password属性对应的setter方法 public void setPassword(String password){ this.password = password; }//处理用户请求的execute方法public String execute() throws Exception{//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success字符串//否则返回error的字符串 if (getUsername().equals("scott")&& getPassword().equals("tiger") ){ return "success"; }else{ return "error"; } }//完成输入校验需要重写的validate方法public void validate(){//如果用户名为空,或者用户名为空字符串if (getUsername() == null || getUsername().trim().equals("")){//添加表单校验错误addFieldError("username", "user.required");}//当密码为空,或者密码为空字符串时,添加表单校验错误if (getPassword() == null || getPassword().trim().equals("")){addFieldError("password", "pass.required");}}}
上面的Action类重写了validate方法,该方法会在执行系统的execute方法之前执行,如果执行该方法之后,Action类的fieldErrors中已经包含了数据校验错误,请求将被转发到input逻辑视图处。
为了在校验失败后,系统能将视图转入input处,必须在配置该Action时配置input属性。下面是修改后login Action的配置片段:
<!-- 定义login的Action --><action name="Login" class="lee.LoginAction"><!-- 定义input的逻辑视图名,对应login.jsp页面 --><result name="input">/login.jsp</result><!-- 定义error的逻辑视图名,对应error.jsp页面 --><result name=" success ">/error.jsp</result><!-- 定义welcome的逻辑视图名,对应welcome.jsp页面 --> <result name="success">/welcome.jsp</result> </action>
对比上面的Action配置与前面的Action配置,我们发现该Action配置片段中增加了input逻辑视图的配置,该逻辑视图映射到login.jsp页面。
前面已经提到:当用户提交请求时,请求得到execute方法处理之前,先会被validate方法处理,如果该方法处理结束后,Action的fieldErrors里的校验错误不为空,请求将被转发给input逻辑视图。如果我们不输入用户名、密码而直接提交表单,将看到如图2.13所示的界面。
看到这里也许读者觉得非常神奇:我们仅仅在Action添加了数据校验错误,并未在输入页面输出这些校验错误信息,但图2.13所示的页面,却可以看到页面已经输出了这些校验信息——这是因为Struts 2的标签,上面的JSP页面中表单使用的并不是HTML表单,而是用了<s:form .../>标签,Struts 2的<s:form ... />标签已经具备了输出校验错误的能力。
提示
但上面的程序还存在一个问题:校验信息的国际化。查看上面的Action类代码发现:重写validate方法时,如果发生校验失败的问题,校验错误的提示信息是以硬编码方式写死了——这就失去了国际化的能力。
实际上,ActionSupport类已经提供了国际化信息的能力,它提供了一个getText(String key)方法,该方法用于从资源文件中获取国际化信息。为了让校验信息支持国际化,再次改写Action里的validate方法,改写后的validate方法代码如下:
//执行数据校验的validate方法public void validate(){//如果用户名为空,或者为空字符串if (getUsername() == null || getUsername().trim().equals("")){//添加校验错误提示,使用getText方法来使提示信息国际化addFieldError("username", getText("user.required"));}if (getPassword() == null || getPassword().trim().equals("")){addFieldError("password", getText("pass.required"));}}
在上面的validate方法中,添加校验错误提示时,并不是直接给出了错误提示的字符串,而是调用了getText方法来获取错误提示。因为在Action中,使用getText方法来获取了两个国际化提示:user.required和pass.required,因此应该在国际化资源文件中添加这两条提示信息。
提示
此时,如果没有任何输出,直接提交登录表单,将看到如图2.14所示的界面。
只需用到attribute
//获取requestActionContext ctx = ActionContext.getContext();ctx.put("request", "request");//获取SessionMap<String,Object> session = ctx.getSession();session.put("session", "session");//获取ServletContextMap<String,Object> appliction = ctx.getApplication();appliction.put("appliction", "appliction");
获得HttpServletRequest
代码获得
HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();HttpSession session = request.getSession();//不要在Action构造器里调用,可能还没初始化好ServletContext servletContext = ServletActionContext.getServletContext();
接口获得
如果有多个Action需要用到request,可以写个Action继承接口,使用request的Action继承再它.
/*继承ServletRequestAware(获得request),ServletResponseAware(获得response),ServletContextAware(获得ServletContext),SessionAware(获得Session)接口*/public class FormAction implements ServletRequestAware,ServletResponseAware{ private HttpServletRequest request; private HttpServletResponse response; //拦截器会把request注入到变量中 public void setServletRequest(HttpServletRequest req) { this.request = req; } public void setServletResponse(HttpServletResponse res) { this.response = res; }}
默认方法
//Struts2中默认访问的是Action中execute方法//url:http://127.0.0.1:8080/Struts2Pro/hello.action(访问hello指定的Action中的execute方法)public String execute() { return "success";}
访问Action中多个方法
动态方法调用
只要在url中指定方法名称就可以了. 如:要访问HelloAction中的add()方法 url:http://127.0.0.1:8080/Struts2Pro/hello!add.action (加!和方法名字)
<!-- 在struts.xml中配置可以关闭动态方法(默认是激活,可能会让用户方法没有公开的方法,最好不用) --><constant name="struts.enable.DynamicMethodInvocation" value="false" />
配置文件中多个方法
配置多个方法
<!-- url:http://127.0.0.1:8080/Struts2Pro/userActionAdd.action 访问FormAction中的add方法 --><action name="userActionAdd" class="com.struts2.form.FormAction" method="add"><!-- url:http://127.0.0.1:8080/Struts2Pro/userActionUpdate.action 访问FormAction中的update方法 --><action name="userActionUpdate" class="com.struts2.form.FormAction" method="update">
使用通配符调用多个方法
<!-- name="*_*" class="com.struts2.form.{1}Action" method="{2}" url:user_list.action 就是调用userAction中list方法. name="*_*_*"url:user_list_abd.actionmethod="{1}"->user(第一个*对应的字符串)method="{2}"->list(第二个*对应的字符串)method="{3}"->abd(第三个*对应的字符串)--><action name="userAction_*" class="com.struts2.form.FormAction" method="{1}">
Struts2标签不支持el表达式,只能使用OGNL.
1.OGNL分为Object Stack和Context Map. 把动作和相关对象压入Object Stack. 把各种映射关系(一些Map类型的对象)压入Context Map.(parameters,request,session,application,attr) OGNL表达式加上一个前缀"#",访问Context Map. 没加访问Object Stack. 2.OGNL访问数组 //String[] colors = {"blue","green","red"}; colors[0]//访问第一个元素 colors.length//访问长度 3.OGNL访问List countries[0]//访问第一个元素 countries.size//访问countries.size() countries.isEmpty//访问countries.isEmpty() 创建List {"a","b","c"}//创建一个由3个String构成的List 4.OGNL访问Map cities["CA"]或者cities['CA']//访问cities中key为CA的元素 cities.size//访问cities.size() cities.isEmpty//访问cities.isEmpty() 创建Map {"CA":"S","WA":"O","UT":"ST"} %{}里面的表达式会被求值(%{#request.user.age>40}->true or false,%{1+6}->7)
类型对应的类
Chain(chain) 构成一条动作链Dispatcher(dispatcher) 默认类型,转发FreeMarker(freemarker) 用于与FreeMarker的集成HttpHeader(httpheader) 把HTTP标头发送回用户Redirect(redurect) 重定向到另一个URLRedirectAction(redirectAction) 重定向到另一个ActionStream(stream) 把一个InputStream流发送给浏览器(下载用)Velocity(Velocity) 用于与Velocity技术的集成XSLT(xslt) 用于与XML/XSLT技术的集成PlainText(plaintext) 发送普通文本,通常用来显示JSP页面的源代码
Chain
<!--Chain用途是构成一条动作链:前一个动作把控制权转交给后一个动作,而前一个动作的状态在后一个动作里仍保持着.动作链能不用就不用, 有可能把一套连续动作弄成一团乱.--><package name="package1" extends="struts-default"> <action name="action1" class="..."> <result type="chain">action2</result> </action> <action name="action2" class="..."> <result type="chain"> <param name="actionName">action3</param> <param name="namespace">/namespace2</param> </result> </action></package><package name="package2" namespace="/namespace2" extends="struts-default"> <action name="action3" class="..."> <result>/view.jsp</result> </action></package>
Dispatcher
<!-- 转发到JSP,result默认类型 --><result name="...">/view.jsp</result><!--或者--><result name="..."> <param name="location">/view.jsp</param></result>
HttpHeader
<!-- 把一个HTTP状态发送给浏览器 --><action name="CatchAll"> <result type="httpheader"> <param name="status">404</param> </result></action>
Redirect
<!-- 重定向 参数:location:重定向的目的地 parse: 表明是否把location参数的值视为一个OGNL表达式来解释,默认值为true--><action name="..." class="..."> <result name="success" type="redirect"> <!-- 内部资源 --> /jsp/Product.jsp <!-- Action带动态参数(${userName}值为本Action中的userName属性值) --> UserAction.action?userName=${userName} <!-- 外部资源(如果需要使用&和+之类的特殊字符必须使用转义序列.如:&改成&) http://www.google.com?user=1&site=4 转成:http://www.google.com?user=1&site=4 --> http://www.google.com </result></action>
RedirectAction
<!-- 重定向到一个Action 参数:actionName:指定重定向Action的名字 namespace: 指定重定向Action的命名空间(没有此参数,与本action同一个命名空间)--><result type="redirectAction">UserAction</result><!-- 或者 --><result type="redirectAction"> <param name="actionName">UserAction</param> <!-- 参数 --> <param name="userId">xyz</param> <param name="area">ga</param><result><!-- 生成URL:UserAction.action?userId=xyz&area=ga -->
PlainText
<!-- 通常被用来发送JSP页面的源代码 --><action name="source_show" class="..."> <result name="success" type="plaintext">/jsp/Menu.jsp</result></action>
<!-- 访问request必须要加# --> <p>赋值,取值</p> <!-- 页面定义变量(本页赋值用name要加#取值),default默认值.--> <!-- 赋值字符串要加'',不然是去Action中找对应的变量.value="test"->在Action中找test变量 --> <s:set id="test1" value="'test1'"></s:set> <!-- #request.get('javax.servlet.forward.context_path')必须经过Action转发到jsp才有值,直接访问jsp无值 --> <s:set id="msg" value="#request.get('javax.servlet.forward.context_path')"/> s:<s:property value="#msg" default="Struts2"/><br/> el:${msg}<br/> <!-- 取Action中变量的值不用加# --> <s:property value="user.name"/><br/> <!-- Action中的变量放在request中 --> --${requestScope.user}||<br/> <p><b>if标签:</b> If标签用来控制基本的条件处理流程,通常和else标签或者elseif标签连用。(%{}可加可不加)</p> <!-- test必须,支持表达式(不支持el表达式) --> <s:if test="#request.user!=null"> <div>user!=null</div> <s:if test="%{#request.user.age>40}"> <div>中年人</div> </s:if> <s:elseif test="%{#request.user.age>20}"> <div>年轻人</div> </s:elseif> <s:else> <div>小孩</div> </s:else> </s:if> <s:else> <div>user==null</div> </s:else> <p><b>iterator标签:</b> 对集合迭代 </p> 迭代List<br/> <!-- 判断是否为空 --> <s:if test="(userList!=null)&&(!userList.isEmpty())"> <div>userList</div> <s:iterator value="#request.userList" id="u" status="st"> index:<s:property value="#st.index+1"/> 是否第一个:<s:property value="#st.first"/> 是否最后一个:<s:property value="#st.last"/> 是否偶数:<s:property value="#st.even"/> 是否奇数:<s:property value="#st.odd"/> <br/> <s:property value="#u.name"/> <s:property value="#u.age"/> <!-- 格式化日期 --> <s:date name="#u.birthday" format="yyyy-MM-dd HH:mm:ss" /> <br/> </s:iterator> </s:if> <s:else> <div>null</div> </s:else> 迭代Map<br/> <s:if test="(userMap!=null)&&(!userMap.isEmpty())"> <div>userMap</div> <s:iterator value="#request.userMap" id="map" status="st"> index:<s:property value="#st.index+1"/> 是否第一个:<s:property value="#st.first"/> 是否最后一个:<s:property value="#st.last"/> 是否偶数:<s:property value="#st.even"/> 是否奇数:<s:property value="#st.odd"/> <br/> <s:property value="#map.key"/> <s:property value="#map.value.name"/> <s:property value="#map.value.age"/> <!-- 格式化日期 --> <s:date name="#map.value.birthday" format="yyyy-MM-dd HH:mm:ss" /> <br/> </s:iterator> </s:if> <s:else> <div>null</div> </s:else> <p><b>append标签:</b> 对多个集合进行合并 </p> <br/> 合并List <br/> <s:append id="newList"> <s:param value="#request.userList"></s:param> <s:param value="#request.userList"></s:param> </s:append> <s:iterator value="#newList" id="u" status="st"> index:<s:property value="#st.index+1"/> 是否第一个:<s:property value="#st.first"/> 是否最后一个:<s:property value="#st.last"/> 是否偶数:<s:property value="#st.even"/> 是否奇数:<s:property value="#st.odd"/> <br/> <s:property value="#u.name"/> <s:property value="#u.age"/> <!-- 格式化日期 --> <s:date name="#u.birthday" format="yyyy-MM-dd HH:mm:ss" /> <br/> </s:iterator> <br/> List和Map合并,结果为Map <br/> <s:append id="newListMap"> <s:param value="#request.userList"></s:param> <s:param value="#request.userMap"></s:param> </s:append> <s:iterator value="#newListMap" id="map" status="st"> index:<s:property value="#st.index+1"/> 是否第一个:<s:property value="#st.first"/> 是否最后一个:<s:property value="#st.last"/> 是否偶数:<s:property value="#st.even"/> 是否奇数:<s:property value="#st.odd"/> <br/> <s:property value="#map.key"/> <s:property value="#map.value.name"/> <s:property value="#map.value.age"/> <!-- 格式化日期 --> <s:date name="#map.value.birthday" format="yyyy-MM-dd HH:mm:ss" /> <br/> </s:iterator> <!-- 显示栈里的参数信息 --> <s:debug></s:debug>
<!-- action="userAction!%{tip}"动态方法tip为Action中的变量 submit不加method --> <s:form action="userAction" namespace="/form" method="POST"> <!-- userBean.id为Action中属性userBean中id的值 --> <s:hidden name="userBean.id"></s:hidden> <s:textfield name="userBean.name" label="用户名" ></s:textfield> <s:textfield name="userBean.age" label="年龄" ></s:textfield> <s:textfield name="userBean.birthday" label="生日" > <!-- 格式化日期 --> <s:param name="value"> <s:date name="userBean.birthday" format="yyyy-MM-dd" /> </s:param> </s:textfield> <!-- 密码不能回填 --> <s:password name="userBean.password" label="密码" ></s:password> <s:textarea name="userBean.des" label="描述" cols="35" rows="8"></s:textarea> <!-- 这种checkbox显示出来是一行只有一个checkbox <s:iterator value="likeList"> <s:checkbox name="userBean.likes" label="%{name}" fieldValue="%{id}"></s:checkbox> </s:iterator> --> <!-- 这种是一行多个 --> <s:checkboxlist list="likeList" name="userBean.likes" listKey="id" listValue="name" label="爱好"></s:checkboxlist> <!-- 下拉框 <s:select list="likeList" listKey="id" listValue="name" headerKey="-1" headerValue="请选择爱好"></s:select> --> <!-- value="1" 设置默认,但是好像设置了不能回填 --> <s:radio list="#{'1':'男','2':'女'}" label="性别" name="userBean.sex"></s:radio> <!-- value显示值,method调用方法 --> <s:submit value="%{tip}" id="submitBut" method="%{tip}"></s:submit> </s:form>
Struts2
文件上传
1.jsp页面
<s:form action="fileAction" namespace="/file" method="POST" enctype="multipart/form-data"> <!-- name为后台对应的参数名称 --> <s:file name="files" label="file1"></s:file> <s:file name="files" label="file2"></s:file> <s:file name="files" label="file3"></s:file> <s:submit value="提交" id="submitBut"></s:submit></s:form>
2.Action
//单个文件上传可以用 File files,String filesFileName,String filesContentType//名称要与jsp中的name相同(三个变量都要生成get,set)private File[] files;// 要以File[]变量名开头private String[] filesFileName;// 要以File[]变量名开头private String[] filesContentType;private ServletContext servletContext;//Action调用的上传文件方法public String execute() { ServletContext servletContext = ServletActionContext.getServletContext(); String dataDir = servletContext.getRealPath("/file/upload"); System.out.println(dataDir); for (int i = 0; i < files.length; i++) { File saveFile = new File(dataDir, filesFileName[i]); files[i].renameTo(saveFile); } return "success";}
3.配置上传文件临时文件夹(在struts.xml中配置)
<constant name="struts.multipart.saveDir" value="c:/temp"/>
文件下载
1.下载的url(到Action)
<a href="${pageContext.request.contextPath}/file/fileAction!down.action">下载</a>
2.struts.xml配置
<package name="file" namespace="/file" extends="struts-default"> <action name="fileAction" class="com.struts2.file.FileAction"> <!-- 下载文件配置 --> <!--type 为 stream 应用 StreamResult 处理--> <result name="down" type="stream"> <!-- 不管实际类型,待下载文件 ContentType 统一指定为 application/octet-stream 默认为 text/plain --> <param name="contentType">application/octet-stream</param> <!-- 默认就是 inputStream,它将会指示 StreamResult 通过 inputName 属性值的 getter 方法, 比如这里就是 getInputStream() 来获取下载文件的内容,意味着你的 Action 要有这个方法 --> <param name="inputName">inputStream</param> <!-- 默认为 inline(在线打开),设置为 attachment 将会告诉浏览器下载该文件,filename 指定下载文 件保有存时的文件名,若未指定将会是以浏览的页面名作为文件名,如以 download.action 作为文件名, 这里使用的是动态文件名,${fileName}, 它将通过 Action 的 getFileName() 获得文件名 --> <param name="contentDisposition">attachment;filename="${fileName}"</param> <!-- 输出时缓冲区的大小 --> <param name="bufferSize">4096</param> </result> </action> </package>
3.Action
//Action调用的下载文件方法 public String down() { return "down"; } //获得下载文件的内容,可以直接读入一个物理文件或从数据库中获取内容 public InputStream getInputStream() throws Exception { String dir = servletContext.getRealPath("/file/upload"); File file = new File(dir, "icon.png"); if (file.exists()) { //下载文件 return new FileInputStream(file); //和 Servlet 中不一样,这里我们不需对输出的中文转码为 ISO8859-1 //将内容(Struts2 文件下载测试)直接写入文件,下载的文件名必须是文本(txt)类型 //return new ByteArrayInputStream("Struts2 文件下载测试".getBytes()); } return null; } // 对于配置中的 ${fileName}, 获得下载保存时的文件名 public String getFileName() { String fileName ="图标.png"; try { // 中文文件名也是需要转码为 ISO8859-1,否则乱码 return new String(fileName.getBytes(), "ISO8859-1"); } catch (UnsupportedEncodingException e) { return "icon.png"; } }
1.导入jsonplugin包
Struts2.16:导入jsonplugin-0.34.jar包(下载包)和commons-logging-1.0.4.jar(Struts2 lib下有)
Struts2.18导入struts2-json-plugin-2.1.8.1.jar(Struts2 lib下有)
2.struts.xml中package 中extends="json-default"
<package name="json" namespace="/json" extends="json-default">
3.result 中type="json"
<!-- 封装所以的get开头的方法 --><result type="json" name="user"></result><!-- 只包含user.id属性 --><result type="json" name="user"> <param name="includeProperties"> user\.id </param></result><!-- 不包含user属性 --><result type="json" name="list"> <param name="excludeProperties"> user </param></result><!-- 根对象只包含user --><result type="json"> <param name="root"> user </param> </result> <!-- "root"对象中父类的field(属性)不会(会?) 默认存放到 JSON数据中,如果不想这样做,需要在配置时指定 ignoreHierarchy 为 false: --><result type="json"> <param name="ignoreHierarchy">false</param> </result>
4.避免使用get开头的action方法
在属性get方法上面加@JSON(name="newName")json中的名称@JSON(serialize=false) 属性不被加入json@JSON(format="yyyy-MM-dd") 格式化日期
5.在action中赋值,返回对应的result字符串
使用response
//直接调用responseOut方法 public void responseOut() throws Exception { StringBuilder sb = new StringBuilder(); sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); sb.append("<users>"); sb.append(" <user id=\"50\">"); sb.append(" <userName>abc</userName>"); sb.append(" </user>"); sb.append("</users>"); //得到response HttpServletResponse response = ServletActionContext.getResponse(); //设置编码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/xml;charset=utf-8"); response.setHeader("Cache-Control", "no-cache"); PrintWriter out = response.getWriter(); out.write(sb.toString()); out.flush(); out.close(); }
UserBean
//要添加set,getpublic class UserBean { private Long id; private String name; private String password; private int age; private Date birthday; private Long sex; private Set<Long> likes; private String des;//描述}public class LikeBean { private Long id; private String name;}
FormAction
public class FormAction{ //属性要生成get,set //标记(添加,修改) private String tip; private UserBean userBean; private List<LikeBean> likeList; private List<UserBean> userList; //到列表页面 public String list(){ userList = new ArrayList<UserBean>(); userList.add(new UserBean("abc",19,new Date())); userList.add(new UserBean("def",70,new Date())); userList.add(new UserBean("ghi",40,new Date())); return "list"; } //到添加页面 public String toAdd(){ likeList = new ArrayList<LikeBean>(); likeList.add(new LikeBean(new Long(1),"上网")); likeList.add(new LikeBean(new Long(2),"读书")); likeList.add(new LikeBean(new Long(3),"游戏")); tip = "add"; return "info"; } //添加方法,Struts2会自动把对应的值赋值给userBean public String add(){ System.out.println(userBean); return "toList"; } //到更新页面,取出值,设置标记 public String toUpdate(){ likeList = new ArrayList<LikeBean>(); likeList.add(new LikeBean(new Long(1),"上网")); likeList.add(new LikeBean(new Long(2),"读书")); likeList.add(new LikeBean(new Long(3),"游戏")); tip = "update"; System.out.println("update name:"+userBean.getName()); userBean = new UserBean("update",100,new Date()); userBean.setId(new Long(101)); userBean.setSex(new Long(2)); userBean.setDes("Struts2用户"); Set<Long> likes = new HashSet<Long>(); likes.add(new Long(2)); likes.add(new Long(3)); userBean.setLikes(likes); return "info"; } //更新方法 public String update(){ System.out.println(userBean); return "toList"; } //删除方法 public String delete(){ System.out.println("del name:"+userBean.getName()); return "toList"; } }
struts.xml配置
<struts> <package name="form" namespace="/form" extends="struts-default"> <!-- 使用通配符调用多个方法,method为*对应的字符串 --> <action name="userAction_*" class="com.struts2.form.FormAction" method="{1}"> <!-- 方法返回的字符串对应name,再转发到页面 --> <result name="list">/form/list.jsp</result> <result name="info">/form/info.jsp</result> <!-- 重定向Action,可以有Action名字和空间,参数 --> <result name="toList" type="redirectAction"> <!-- 空间参数,不写代表和当前Action同一个空间 <param name="namespace">form</param> --> <!-- 重定向Action的名称 --> <param name="actionName">userAction_list</param> <!-- url带的参数,${userBean.name}是动态参数,值为Action的属性userBean中name的值 --> <param name="userName">${userBean.name}</param> <param name="userAge">${userBean.age}</param> </result> </action> </package></struts>
jsp页面
1.list(列表页面)
<!-- 添加标签 --><%@ taglib prefix="s" uri="/struts-tags" %> <div><a href="${pageContext.request.contextPath}/form/userAction_toAdd.action">添加</a></div> <div> <!-- 判断用户是否为空 --> <s:if test="(userList!=null)&&(!userList.isEmpty())"> <div>用户列表</div> <!-- 遍历用户 --> <s:iterator value="#request.userList" id="u" status="st"> <s:property value="#st.index+1"/> <s:property value="#u.name"/> <s:property value="#u.age"/> <!-- 格式化日期 --> <s:date name="#u.birthday" format="yyyy-MM-dd HH:mm:ss" /> <a href="${pageContext.request.contextPath}/form/userAction_toUpdate.action?userBean.name=${u.name}">修改</a> <a href="${pageContext.request.contextPath}/form/userAction_delete.action?userBean.name=${u.name}">删除</a> <br/> </s:iterator> </s:if> <s:else> <div>无用户</div> </s:else> </div>
2.info.jsp(添加和修改页面)
<!-- 添加标签 --><%@ taglib prefix="s" uri="/struts-tags" %> <!-- 显示标记(添加/修改) --> <s:property value="tip"/> <!-- action="userAction_%{tip}"tip为Action中的标记变量 submit不加method --> <s:form action="userAction" namespace="/form" method="POST"> <!-- userBean.id为Action中属性userBean中id的值 --> <s:hidden name="userBean.id"></s:hidden> <s:textfield name="userBean.name" label="用户名" ></s:textfield> <s:textfield name="userBean.age" label="年龄" ></s:textfield> <s:textfield name="userBean.birthday" label="生日" > <!-- 格式化日期 --> <s:param name="value"><s:date name="userBean.birthday" format="yyyy-MM-dd" /></s:param> </s:textfield> <!-- 密码不能回填 --> <s:password name="userBean.password" label="密码" ></s:password> <s:textarea name="userBean.des" label="描述" cols="35" rows="8"></s:textarea> <!-- 这种checkbox显示出来是一行只有一个checkbox <s:iterator value="likeList"> <s:checkbox name="userBean.likes" label="%{name}" fieldValue="%{id}"></s:checkbox> </s:iterator> --> <!-- 这种是一行多个 --> <s:checkboxlist list="likeList" name="userBean.likes" listKey="id" listValue="name" label="爱好"></s:checkboxlist> <!-- 下拉框 <s:select list="likeList" listKey="id" listValue="name" headerKey="-1" headerValue="请选择爱好"></s:select> --> <!-- value="1" 设置默认,但是好像设置了不能回填 --> <s:radio list="#{'1':'男','2':'女'}" label="性别" name="userBean.sex"></s:radio> <s:submit value="%{tip}" id="submitBut" method="%{tip}"></s:submit> </s:form>
1.定义properties文件
资源文件查找顺序
JAVA国际化如果系统同时存在资源文件、类文件,系统将以类文件为主,而不会调用资源文件。对于简体中文的Locale,ResourceBundle搜索资源的顺序是:(1)baseName_zh_CN.class(2)baseName_zh_CN.properties(3)baseName_zh.class(4)baseName_zh.properties(5)baseName.class(6)baseName.properties/* Struts2找不到对应语言的配置文件时,会先找系统语言对应的配置文件,再找不到才使用baseName.properties */
国际化分为三类:全局的,包级别的,类级别的
全局的: 1.在struts.xml中的<constant name="struts.custom.i18n.resources" value="message"></constant>指定baseName 国际化文件名为:baseName_语言名_国家名.properties(如:message_zh_CN.properties) 2.全局的国际化资源文件放在src下面 包级别的: 1.包级别的国际化资源文件放在该包下面 2.命名规则为:package_语言名_国家名.properties(如:package_zh_CN.properties) 其中package不变,不是指的是包名,每个包的国际化文件命名都这样 类级别的: 1.与该类放在同一目录中 2.命名规则为:类名_语言名_国家名.properties(如:RegisterAction_zh_CN.properties) 若同一key 在上面三个国际化文件中都为value值则:(优先级)类级别的>包级别的>全局的
2.在jsp中访问国际化资源文件
<!-- 输出国际化 --> <!-- name为国际化文件中的key --> <s:text name="hello"> <!-- 若该国际化文件的value中有{0}则可用下面的标签把参数传进去 --> <s:param>mengya</s:param> <s:param><s:property value="firstName"/></s:param> </s:text> <s:property value="%{getText('customer.contact')}"/> 传参数 <s:property value="%{getText('customer.contact','sh')}"/> 定义变量,加var属性 <s:text name="greetings" var="msg"/> <s:property value="#msg"/> <!-- 指定特定的国际化文件,name为全局国际化文件的baseName --> <s:i18n name="temp"> <!-- 下面的<s:text>标签与上面的用法一样 --> <s:text name="hello"> <s:param>mengya</s:param> </s:text> </s:i18n> 表单国际化: 1.theme不能为simple如:<s:form action="register">(默认的theme不是simple) 2.使用key如:<s:textfield name="username" key="" id="usernameId"></s:textfield> 3.或者使用getText方法<s:textfield name="username" label="%{getText('customer.name')}"/>
3.在Action中访问国际化资源文件,该Action继承了ActionSupport类
this.getText("username.invalid") 若该key对应的value需要参数则: this.getText("username.invalid",new String[]{username}) 或 List list = new ArrayList(); list.add(username); this.getText("username.invalid",list) 如: if (null == username || username.length() < 6 || username.length() > 10) { List list = new ArrayList(); list.add(username); this.addActionError(this.getText("username.invalid",new String[]{username})); } 该国际化资源文件中的key和value为: username.invalid = \u7528\u6237\u540d "{0}" \u586b\u5199\u4e0d\u6b63\u786e
4.在输入验证框架访问国际化资源文件
<!-- 使用<message key="..."></message> -> <field-validator type="requiredstring"> <param name="trim">true</param> <message key="username.invalid"></message> </field-validator>
5.动态改变语言
只有在url传入request_locale=en_US就可以指定为en_US的语言
1.如果配置文件是en_US结尾,传入en,en_US都可以找到
2.如果配置文件是en结尾,只能传入en,传入en_US会找不到,从而找默认的配置文件(en的范围>en_US,使用英语的国家不止美国一个)
<a href="${pageContext.request.contextPath}/i18n/i18nAction?request_locale=en_US">English</a>
6.使用类来代替properties文件
//继承ListResourceBundle实现getContents方法public class MyCustomResourceBundle extends ListResourceBundle { public Object[][] getContents() { if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) < 12) { return contents1; } else { return contents2; } } static final Object[][] contents1 = { { "greetings", "中午好 {0}" }, { "farewell", "再见" } }; static final Object[][] contents2 = { { "greetings", "你好 {0}" }, { "farewell", "再见" } };}//en对应的字符串public class MyCustomResourceBundle_en extends ListResourceBundle { public Object[][] getContents() { if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) < 12) { return contents1; } else { return contents2; } } static final Object[][] contents1 = { { "greetings", "Good morning {0}" }, { "farewell", "Good bye" } }; static final Object[][] contents2 = { { "greetings", "Hello {0}" }, { "farewell", "Good bye" } };}//jsp中使用<s:i18n name="com.resourcebundle.MyCustomResourceBundle"> <s:text name="greetings"> <s:param>Jon</s:param> </s:text>. <s:text name="farewell"/></s:i18n>
Action配置中一定要设置input返回页面
添加验证只要创建验证的xml文件
1.创建xml文件名
验证Action中全部方法
在Action同包下,创建:Action类名-validation.xml
如:ValidateAction创建ValidateAction-validation.xml
验证Action中单个方法
<!-- 每个方法单独配置一个Action --><!-- 在Action同包下,创建:Action类名-action方法配置名称-validation.xml --><action name="validateAdd" class="com.struts2.validator.ValidateAction" method="add"><!-- 要创建ValidateAction-validateAdd-validation.xml --><!-- 使用通配符配置 --><!-- 在Action同包下,创建:Action类名-action方法对应的名称-validation.xml --><action name="validate_*" class="com.struts2.validator.ValidateAction" method="{1}"><!-- 要创建ValidateAction-validate_add-validation.xml,validate_add为访问这个action方法的路径 -->
注意事项
注意:1.要验证的方法不能叫input.2.这样配置在form表单中要在<s:form action="validate_add">中action写好名称,不能写action="validate_",然后<s:submit value="提交"method="add" /> 这样会找不到对应的配置文件,跳过验证.3.如果验证出错,返回input页面时,那些存在ValueStack中的值会丢失,可以将Action实现Preparable接口,然后prepare()方法里初始化添加页面需要的值.4.如果使用Preparable接口,必须在action配置中添加<interceptor-ref name="paramsPrepareParamsStack" />.这样prepare()才能得到form提交的参数.
2.创建xml内容
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"><validators> <!-- 要验证的字段名称 --> <!-- 要验证Action中UserBean的id字段,name="userBean.id"(userBean为Action中的变量名) --> <field name="mail"> <!-- type要验证的类型,short-circuit(默认false),true含义,如果当前验证失败了,下面的验证就不执行了.如requiredstring失败了,email就不验证了. --> <!-- field-validator下面可以有多个param元素,但是最多只能有一个message --> <field-validator type="requiredstring"> <param name="trim">true</param> <message>Please enter a mail</message> </field-validator> <field-validator type="email"> <message> Invalid MAIL </message> </field-validator> </field></validators>
Struts内建验证程序(type的值)
required
保证字段的值不是空值null.空字符串不是空值null.
<field name="userName"> <field-validator type="required"> <message>Please enter a user name</message> </field-validator></field>
requiredstring
保证字段不是空值null,也不是空白(empty).
param:trim(boolean) ->true->去除前后空格
<field name="userName"> <field-validator type="requiredstring"> <param name="trim">true</param> <message>Please enter a user name</message> </field-validator></field><field name="password"> <field-validator type="requiredstring"> <param name="trim">false</param> <message>Please enter a password</message> </field-validator></field>
int
验证字段值是否可以转换为一个整数.
param: min(int);max(int)
<field name="yeaar"> <field-validator type="int"> <param name="min">1999</param> <param name="max">2010</param> <message>year:1999-2010</message> </field-validator></field>
date
验证给定日期字段的值是否在一个给定的范围内.
param:max(date);min(date)
<field name="borthday"> <field-validator type="int"> <!-- 格式取决于当前地理时区 --> <param name="min">1999-01-01</param> <param name="max">2010-01-01</param> <message>birthday:1999-2010</message> </field-validator></field>
给定的String值是否是一个电子邮件地址
<field name="email"> <field-validator type="email"> <message>Invalid email</message> </field-validator></field>
url
给定的String值是否是一个合法的URL(要有前缀)
<field name="url"> <field-validator type="url"> <message>Invalid URL</message> </field-validator></field>
expression,fieldexpression
验证给定字段是否满足一个OGNL表达式.
区别:expression 不是一个字段验证程序,失败时将生成一个动作错误.(JSP中调用
<actionerror>
</actionerror>
才显示出错信息)fieldexpression 是一个字段验证程序,失败时将抛出一个字段错误.(对字段验证)
param:expression(String)OGNL表达式
expression:
public class ExpressionTestAction { //属性生成get,set private int min; private int max;}<validator type="expression"> <param name="expression"> max > min </param> <message> Maximum temperature must be greater than Minimum temperature </message></validator><!-- jsp --><s:actionerror/>
fieldexpression:
public class FieldExpressionTestAction { //属性生成get,set private int min; private int max;}<!-- 对字段验证 --><field name="max"> <field-validator type="fieldexpression"> <param name="expression"> max > min </param> <message> Maximum temperature must be greater than Minimum temperature </message> </field-validator></field>
visitor
把同一个验证程序配置文件用于多个动作(对一个Bean写验证文件,每个使用的Action只要引用)
//UserBeanpublic class UserBean { //属性get,set private String name; private int age;}//UserBean-validation.xml(和UserBean放在同一个包中)<field name="name"> <field-validator type="requiredstring"> <message>用户名必须</message> </field-validator></field><field name="age"> <field-validator type="int"> <param name="min">18</param> <param name="max">99</param> <message>Age must be between 18 and 99</message> </field-validator></field>//Action的validation.xml<!-- userBean变量名 --><field name="userBean"> <field-validator type="visitor"> <!-- message会和UserBean验证中的message一起显示 --> <message>用户: </message> </field-validator></field>
如果另一个Action对UserBean使用另一个标准的验证,可以创建新的验证文件
//UserBean-specific-validation.xml<!-- 和之前的验证不同 --><field name="age"> <field-validator type="int"> <param name="min">30</param> <param name="max">50</param> <message>Age must be between 30 and 50</message> </field-validator></field>//另一个Action的validation.xml<field name="userBean"> <field-validator type="visitor"> <!-- xml中扩展的名字,执行UserBean-specific-validation.xml的验证 --> <param name="context">specific</param> <message>用户1: </message> </field-validator></field>
conversion
检查对某个属性进行类型转换是否会导致一个转换错误
<field name="age"> <field-validator type="conversion"> <message> An age must be an integer. </message> </field-validator></field>
stringlength
验证一个非空的字段值是不是足够的长度
param:minLength(int);maxLength(int);trim(boolean)
<field name="password"> <field-validator type="requiredstring"> <param name="minLength">6</param> <param name="maxLength">14</param> <message>length:6-14</message> </field-validator></field>
regex
给定的值是否与一个给定的正则表达式匹配
param:expression(String)正则表达式;caseSensitive(boolean)是否区别大小写,默认为true;trim(boolean)是否去除前后空格
<field name="phone"> <field-validator type="regex"> <param name="expression"> <![CDATA[\d\d\d\-\d\d\d\-\d\d\d\d]]> </param> <message> Invalid phone number or invalid format </message> </field-validator></field>
3.在action中验证
利用Validateable接口实现验证,实现void validate()方法.
ActionSupport类已经实现了这个接口
//继承ActionSupportpublic class User extends ActionSupport { //属性get,set private String userName; private String password; private static List<String> userNames = new ArrayList<String>(); static { userNames.add("harry"); userNames.add("sally"); } //验证方法 public void validate() { if (userNames.contains(userName)) { //添加出错信息 addFieldError("userName", "'" + userName + "' has been taken."); } }}
4.自定义验证类
要创建一个普通的验证程序(非字段验证程序),扩展ValidatorSupport类.验证失败要从validate方法调用addActionError方法.
要创建一个字段验证程序,扩展FieldValidatorSupport类.验证失败要从validate方法调用addFieldError方法.
如果要能接受参数,要在类中定义一个相应的属性,并生成get,set.
编写类
public class StrongPasswordValidator extends FieldValidatorSupport { //属性 private int minLength = -1; public void setMinLength(int minLength) { this.minLength = minLength; } public int getMinLength() { return minLength; } //验证方法 public void validate(Object object) throws ValidationException { String fieldName = getFieldName(); String value = (String) getFieldValue(fieldName, object); if (value == null || value.length() <= 0) { // use a required validator for these return; } if ((minLength > -1) && (value.length() < minLength)) { addFieldError(fieldName, object); } else if (!isPasswordStrong(value)) { addFieldError(fieldName, object); } } private static final String GROUP_1 = "abcdefghijklmnopqrstuvwxyz"; private static final String GROUP_2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static final String GROUP_3 = "0123456789"; protected boolean isPasswordStrong(String password) { boolean ok1 = false; boolean ok2 = false; boolean ok3 = false; int length = password.length(); for (int i = 0; i < length; i++) { if (ok1 && ok2 && ok3) { break; } String character = password.substring(i, i + 1); System.out.println("character:" + character); if (GROUP_1.contains(character)) { ok1 = true; continue; } if (GROUP_2.contains(character)) { ok2 = true; continue; } if (GROUP_3.contains(character)) { ok3 = true; } } return (ok1 && ok2 && ok3); } }
注册xml
在src下创建validators.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator Config 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd"><validators> <!-- 名称(type对应值),类路径 --> <validator name="strongpassword" class="com.validator.StrongPasswordValidator"/></validators>
使用验证
<field name="password"> <field-validator type="strongpassword"> <param name="minLength">8</param> <message> Password must be at least 8 characters long and contains at least one lower case character, one upper case character, and a digit. </message> </field-validator></field>
- Struts2相关知识整合
- 重新整理struts2与spring整合相关知识
- 相关知识整合
- struts2相关知识
- struts2相关知识
- 【JavaWeb-25】事务管理相关知识、手动/半自动/自动管理事务案例、整合Junit、整合Web、spring和hibernate整合、struts2和spring整合
- Struts2相关知识(一)
- struts2文件上传相关资料收集整合
- Struts2 Spring3 Mybatis 3 整合 相关配置文件
- struts2+Hibernate+spring基础整合相关介绍
- 关于struts2框架配置文件的相关知识
- 细说struts2中一些相关的知识
- struts2-ValueStack相关知识(OGNL)
- struts2的流程和一系列相关知识
- struts2+hibernate+spring整合各个相关的配置文件
- Hibernate和Struts2的整合(相关问题的说明)
- struts2--(3)--一些小的知识----访问web相关元素
- 电商之梳理struts2相关知识---开发基础框架
- 前端MV*框架的意义
- 各种音视频编解码学习详解
- Cocos2d-x纹理优化的一些方案
- Ganglia3.1.7 Install and Config
- 圆形风格的移动应用实例
- Struts2相关知识整合
- php 前一天或后一天的日期
- WEB架构师成长之路之一-走正确的路
- wince 外部程序的关闭和打开
- http://www.trinea.cn/
- Spring事务配置的5种方式
- centos中文输入法设置
- struts 常用的constant作用和配置
- 集群 分布式计算