----Struts 使用技巧----
1 Struts validate
1.1 使用ActionForm的validate()验证
总体思路:这个验证是没有添加验证框架的验证,而是直接通过ActionForm的validate()方法进行系统验证,
进行验证要处理三个方面的问题:
> 配置资源文件:配置ApplicationResources.prop内容,把验证的的内容写道其中;
> 配置FormBean: 配置FormBean中的validate()方法,处理相关验证;
> 配置Jsp:配置JSP中相关信息接受后台验证信息的处理结果;
1.1.1 验证步骤 (验证登录页面中的userName不为空为例)
1.1.1.1 打开userForm的验证
在struts-config.xml中找到相应的ActionMapping内容:
<action-mappings >
<action
attribute="insertUserForm"
name="insertUserForm"
input="regeditUser.jsp"
path="/regedit"
scope="request"
type="com.kevinb.struts.action.RegeditAction"
validate="true"> //注意:本处是最新添加的部分,开启了form的验证功能,不打开进行验证也是无效的;但是不显示默认验证;
<forward name="regeditOk" path="/viewUser.jsp" />
</action>
1.1.1.2 在资源文件中填写相应的错误信息,并且进行验证信息规划 ,在资源文件中添加 :
userName.required=userName is required,please input information...
其中:userName.required是key
userName is required,please input information...是value
userName.required对应后台UserForm中validate()方法中的error.add("userName",new ActionMessage("userName.required"));
和new ActionMessage("key"),对应;
1.1.1.3 在UserForm中的validate()中写代码:
//申请一个error实例,用来存放验证信息
ActionErrors error = new ActionErrors();
//验证用户名称不能够为空
if(userName == null || userName.equals("")){
error.add("userName",new ActionMessage("userName.required"));
}
...
return error;
其中:error.add("userName",new ActionMessage("userName.required"))中
userName:对应页面中的<html:errors property="userName"/>中的property中的内容;
userName.required:对应资源文件中的:userName.required=userName is required,please input information...前半部分;
所以,error.add("key","value")起到了一个连接页面和资源文件的左右,并且处理相关的信息;
注意:ActionErrors的实例用法和Map的用法类似在后台通过error.add("key","value");存入数据,
前台通过:<html:errors property="userName"/><br>进行接受,其中后台中的key的内容一定要和
前台property中的内容完全一致,前台也是通过这个key进行接受后台信息的,接受的内容是
new ActionMessage("userName.required"),其中userName.required是资源文件中的内容的key,
对应资源文件中的:userName.required=userName is required,please input information...
内容,所以前台最后呈现的内容是:userName is required,please input information...
1.1.1.4 在页面中接受错误信息
<html:form action="login.do">
userName:<html:text property="userName"></html:text>
<html:errors property="userName"/><br> //处理错误,打印资源文件中的错误信息;
1.2 使用Struts验证框架进行验证_DynaValidatorForm(适合动态验证Form)
1.2.1 加载验证框架
在struts-config.xml中添加plug-in,在服务启动的时候启动验证框架
--添加位置(message下面):
<message-resources parameter="com.kevinb.struts.ApplicationResources" />
...
--内容:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
1.2.2 创建配置validate.xml
在WEB-INF/下创建validate.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
<form-validation>
<formset>
<form name="userForm"> //需要验证的Form
<field property="regeditDate" depends="required,date"> //需要验证的属性和验证内容
<arg0 key="regeditDate"/> //对应资源文件中的arg0参数,一定要在资源文件中找到同名的内容:如:regeditDate = regeditDate
</field>
<field property="userName" depends="required"> //一个页面中可以有多个验证属性;
<arg0 key="userName"/>
</field>
...
</form>
</formset>
</form-validation>
--实例用户登录验证
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
<form-validation>
<formset>
<form name="userForm">
<field property="userName" depends="required"> //验证用户名不能够为空
<arg0 key="userName"/>
</field>
<field property="userPsw" depends="required,minlength,maxlength"> //验证密码不能为空、最小长度6,最大长度10;
<arg0 key="userPsw"/>
<arg1 name="minlength" key="${var:minlength}" resource="false"/> //验证的长度要通过参数定义的方式使用,定义参数
<var>
<var-name>minlength</var-name> //定义参数名称,与depends="required,minlength,maxlength"同名
<var-value>6</var-value> //定义参数数值
</var>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>10</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
1.2.3 配置资源文件内容
errors.required={0} is required. //通用必填,{0}表示动态传入的属性名称
errors.date={0} is not a date. //通用时间格式验证
regeditDate = regeditDate //验证属性名称,注意这个属性名称一定要和validate.xml中<field property="regeditDate"的property内容一致,
userName = userName //验证属性名称
--实例用户验证
# Resources for parameter 'com.kevinb.struts.ApplicationResources'
# Project ValidatorLogin
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.
errors.maxlength={0} can not be greater than {1} characters.
userName= userName
userPsw= userPsw
1.2.4 jsp页面中的配置
UserName:<html:text property="userName"></html:text>
<html:errors property="userName"/> //在需要验证的字段后添加<html:errors>标签,其中property内容是与资源文件和验证框架中的<field property="regeditDate"
的内容一致;
1.3 使用Struts验证框架进行验证_ValidatorForm(适合验证Form,标准的ActionForm中使用Validator框架)
1.3.1 加载验证框架 (雷同动态Form)
在struts-config.xml中添加plug-in,在服务启动的时候启动验证框架
--添加位置(message下面):
<message-resources parameter="com.kevinb.struts.ApplicationResources" />
...
--内容:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
1.3.2 创建配置validate.xml (雷同动态Form)
在WEB-INF/下创建validate.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
<form-validation>
<formset>
<form name="userForm"> //需要验证的Form
<field property="regeditDate" depends="required,date"> //需要验证的属性和验证内容
<arg0 key="regeditDate"/> //对应资源文件中的arg0参数,一定要在资源文件中找到同名的内容:如:regeditDate = regeditDate
</field>
<field property="userName" depends="required"> //一个页面中可以有多个验证属性;
<arg0 key="userName"/>
</field>
...
</form>
</formset>
</form-validation>
1.3.3 配置资源文件内容 (雷同动态Form)
errors.required={0} is required. //通用必填,{0}表示动态传入的属性名称
errors.date={0} is not a date. //通用时间格式验证
regeditDate = regeditDate //验证属性名称,注意这个属性名称一定要和validate.xml中<field property="regeditDate"的property内容一致,
userName = userName //验证属性名称
1.3.4 在ValidatorForm中的validate方法中(不同于动态Form)
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
System.out.println("----UserForm.validate()----");
//继承父类的验证方法,进行验证
return super.validate(mapping, request);
}
1.3.5 jsp页面中的配置(雷同动态Form)
UserName:<html:text property="userName"></html:text>
<html:errors property="userName"/> //在需要验证的字段后添加<html:errors>标签,其中property内容是与资源文件和验证框架中的<field property="regeditDate"
的内容一致;
--注意每一个Action中的validate="true"(进行验证)默认的是true,只要不是写默认是true;
1.4 验证框架接受错误信息方法(重要):
使用验证框架的时候,接受错误可以采用两种方法;
1.采用与验证字段同名
使用这种方法要保证:<html:errors property="userName"/>中property的内容和验证字段内容一致;
否则页面无法接受错误信息;
2.可以采用通用错误接受
使用这种方法接受错误,可以直接使用<html:errors/>不用设置property内容,这样可以接受这个页面中的全部错误信息;
2. 读取Struts框架的资源文件(ApplicationResources.properties)方法
2.1 方法一:采用输入流的方式读取
代码:
/**
* 读取资源文件 方法二较为简单,推荐使用,但是两种方法都可以达到读取资源文件内容的效果;
* 1.方法一:采用输入流的方式进行读取;
* 主要核心代码:
* --1 定义一个输入流,读取资源文件
* InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("ApplicationResources.properties");
* --2 定义一个Properties的实例;
* Properties props = new Properties();
* --3 把输入流在如属性实例;
* props.load(inputStream);
* --4 通过属性实例取得和key取得属性的内容;
* dbUser = props.getProperty("DBUSER");
*
* 总结:两种方法都得指定资源文件的具体位置;采用方式:
* "com/kevinb/struts/ApplicationResources.properties"
*/
public X(){ //放在构造函授中进行赋值
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/kevinb/struts/ApplicationResources.properties");
Properties props = new Properties();
try {
props.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
dbUser = props.getProperty("DBUSER");
dbPsw = props.getProperty("DBPSW");
dbServer = props.getProperty("DBSERVER");
}
2.2 方法二:采用ResourceBundle.getBundle()方法
/**
* 读取资源文件:
* 2.方法二:采用ResourceBundle.getBundle()方法,但是一定要在getBundle中指定资源文件相对classes所在
* 的位置;
* 主要的核心代码是:
* --1 指定资源文件所在的具体位置 ;
* ResourceBundle bundle = ResourceBundle.getBundle("com/kevinb/struts/ApplicationResources",Locale.CHINA);
* --2 通过key 取得资源文件内条目的具体内容;
* dbUser = bundle.getString("DBUSER");
*/
public X(){ //构造函数
ResourceBundle bundle = ResourceBundle.getBundle("com/kevinb/struts/ApplicationResources",Locale.CHINA);
dbUser = bundle.getString("DBUSER");
dbPsw = bundle.getString("DBPSW");
dbServer = bundle.getString("DBSERVER");
}
3. Java程序兼容汉字
3.1 局部处理方法
3.1.1 修改所有页面的编码格式为:GBK
<%@ page language="java" pageEncoding="GBK"%>
3.1.2 修改FormBean中的setProperty方法
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = ProcessCode.proCode(userName); //注意添加了格式转化
}
只需要修改这一个地方,这样页面验证通过<%@ page language="java" pageEncoding="GBK"%>确定
编码格式,而存入数据库中是通过getProperty方法,存入的数据是setProperty的数据,所以只需要
控制setProperty这一个入口,就可以取得数据;
注意:FormBean中的编码格式,是通过页面中编码确定的<%@ page language="java" pageEncoding="GBK"%>;
3.2 解决Struts中文乱码问题(彻底解决方法,推荐使用)
3.2.1 新建EncodingActionServlet
--扩展ActionServlet,同时复写process方法,设置request.setCharacterEncoding("GBK");
public class EncodingActionServlet extends ActionServlet {
protected void process(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{
request.setCharacterEncoding("GBK");
super.process(request, response);
}
}
3.2.2 修改Web.xml
<servlet-name>action</servlet-name>
<servlet-class>com.kevinb.struts.EncodingActionServlet</servlet-class>
4 创建动态Form
4.1 创建动态form最大的好处是没有具体的FormBean类,动态Form使用方法和普通的formBean方法一致,
但是动态form没有具体的getX()和setX()方法;
4.2 取得和修改属性
--取得:使用get("X")方法
DynaValidatorForm userForm = (DynaValidatorForm) form;// TODO Auto-generated method stub
String userName = ProcessCode.proCode((String)userForm.get("userName"));
String regeditDate = (String)userForm.get("regeditDate");
String userSex = (String)userForm.get("userSex");
--赋值:使用set("X")方法
4.3 使用动态Form注意问题(非常重要)
在页面中如果要使用EL表达式,最好使用BeanUtils.copyProperties(user, userForm);
其中:user是一个专门的bean,如果把动态form数据直接传递到页面使用EL表达式会出现错误,
一定要把数据复制到普通的bean中,再把普通的bean传递到页面使用EL表达式;
5 自定义资源文件
5.1 自定义资源文件过程
5.1.1 建立资源文件
在工程原资源文件所在的目录下复制ApplicationResources.properties重新命名为:X.properties
5.1.2 在struts-config中进行注册
在原注册信息下添加如下内容:
<message-resources parameter="com.kevinb.struts.KevinbProperty" key="kevinb"/>
其中:parameter:表示新文件所在的位置和名称
key:表示给自定义资源文件指定一个唯一的名称,页面中是通过这个key进行调用的;
5.1.3 在jsp中进行调用
5.1.3.1 调用ApplicationResources.properties中的内容
原资源文件中的内容:
proTest=ApplicationResources,hello
info=hello,{0},{1}
页面调用:
<h5>1.1 读取ApplicationResource.properties文件内容不使用bundle,直接使用key读取</h5>
<br><bean:message key="proTest"/><br>
<h5>1.2 读取带有参数的内容</h5>
<bean:message key="info" arg0="Kevinb" arg1="Mark"/>
通过key指定调用资源文件的内容;
5.1.3.2 调用新的自定义文件
资源文件内容:
proTest=KevinbProperty,hello
info=Hello,{0} ,{1}
页面调用(调用自定义文件在调用的时候一定要添加bundle="X",其中X表示在struts-config.xml中的内容key="kevinb"进行对应):
<h5>2.1 读取KevinbProperty.properties中键值为key="proTest"的属性</h5>
<br><bean:message bundle="kevinb" key="proTest"/><br>
<h5>2.1 读取带参数的数据</h5>
<br><bean:message bundle="kevinb" key="info" arg0="hh" arg1="aa"/><br>
6.使用EL表达式
6.1 表达内容是一个普通变量
<%
//传入一个变量
request.setAttribute("para","Kevinb");
%>
<h5>1.表达内容是一个普通变量 </h5>
<br>
para: ${para }
<br>
6.2 表达内容是一个数组
<%
//传入一个数组
Vector<String> v = new Vector<String>();
v.add("Kevinb");
v.add("Jack");
v.add("Mark");
v.add("Herry");
request.setAttribute("user",v);
%>
<h5>2.表达内容是一个数组 </h5>
<br>
<logic:iterate id="list" name="user">
${list }
</logic:iterate>
<br>
6.3 表达内容是一个bean
<%
//定义一个bean
UserBean userBean = new UserBean();
userBean.setUserId("A01");
userBean.setName("Kevinb");
request.setAttribute("userBean",userBean);
%>
<h5>3.表达内容是一个bean </h5>
<br>
id:${userBean.userId }<br>
name: ${userBean.name }
<br>
7 Struts国际化
7.1 建立国际化资源文件
拷贝/com/kevinb/struts/下的ApplicationResources.properties,在本目录粘贴两次,分别命名为:
ApplicationResources_China.properties(负责处理语言是中文的资源,名称可以自定义)和ApplicationResources_en.properties(负责处理语言是英语的资源,名称不可以自定义各式固定)
7.2 填写相应的验证内容,同时按照语言进行填写,中文的资源填写中文(键值必须是英文),英文填写英文;
如进行登录验证,
--中文资源ApplicationResources_China.properties内容:
# Resources for parameter 'com.kevinb.struts.ApplicationResources'
# Project StrutsISOApp
userName.request= 用户名不能为空.
psw.requerst= 密码不能够为空.
--同步英文资源文件内容ApplicationResources_en.properties:
# Resources for parameter 'com.kevinb.struts.ApplicationResources'
# Project StrutsISOApp
userName.request= userName is request.
psw.requerst= password is request.
7.3 编译中文资源文件,在文件所在目录下使用如下命令进行编译:
native2ascii -encoding gb2312 ApplicationResources_China.properties ApplicationResources_zh_CN.properties
确认没有出现任何错误的情况下,完成编译;
说明:
ApplicationResources_zh_CN.properties:是中文资源文件,同时名称式固定的;
通过这个命名可以通过ApplicationResources_China.properties生成ApplicationResources_zh_CN.properties;
ApplicationResources_zh_CN.properties内容如下:
# Resources for parameter 'com.kevinb.struts.ApplicationResources'
# Project StrutsISOApp
hello=/u4f60/u597d /u51ef/u6587
userName.request= /u7528/u6237/u540d/u4e0d/u80fd/u4e3a/u7a7a.
psw.requerst= /u5bc6/u7801/u4e0d/u80fd/u591f/u4e3a/u7a7a.
7.4 这样在IE设置中语言栏中,如果首选中文,验证信息会自动采用ApplicationResources_zh_CN.properties的内容,
如果是英语验证信息会自动采用ApplicationResources_en.properties中的内容;
8. 使用BeanUtils进行数据拷贝;
8.1 引包
import org.apache.commons.beanutils.BeanUtils;
8.2 拷贝数据
BeanUtils.copyProperties(user, userForm);
拷贝顺序是采用从后向前的顺序拷贝,注意拷贝的时候一定要保持字段的名称和属性一致;
9. 使用Action和DispatchAction
9.1 如果Action只有一个方法可以直接使用Action的excute方法;
9.2 如果需要同时使用一个Action的多个方法,需要配置Action
9.2.1 生成extends DispatchAction类
9.2.2 在struts-config.xml中找到相应的action,添加配置:parameter="action"
在jsp中就可以直接使用:
<a href="computer.do?action=functionTest">functionTest</a>
10. 使用下拉数据源
10.1 创建下拉数据源
10.1.1 jsp部分
--嵌入java代码从后台取得数据;
<%
//取得单位下拉数据的内容
DeptAction deptAction = new DeptAction();
List<RsDept> deptList = deptAction.getAllDept();
request.setAttribute("deptList",deptList);
%>
--创建下拉数据源
<tr class="tr0">
<td>
<html:select property="deptId">
<logic:iterate id="dept" name="deptList">
<html:option value="${dept.deptId}">${dept.deptName}</html:option>
</logic:iterate>
</html:select>
<html:errors property="deptId"/>
</td>
</tr>
--配合使用html:select 和 logic:iterator,用logic:iterator取得数据,同时把数据放在html:opention中;
使用logic:iterator从后台获取数据;数据来源是页面中的java代码部分;
10.1.2 action部分
List<RsDept> deptList = deptAction.getAllDept();
--负责从后台取得数据源的数据;
10.2 套用下拉数据源(按照下拉数据源形式显示)
10.2.1 从后台取得已经正常存在的的数据,如:dept_id = 5;
10.2.2 jsp部分
--通过java代码取得数据;
<%
//取得单位下拉数据的内容
DeptAction deptAction = new DeptAction();
List<RsDept> deptList = deptAction.getAllDept();
request.setAttribute("deptList",deptList);
//取得人员信息
EmpInputAction empInputAction = new EmpInputAction();
List<EmpInputForm> empList = empInputAction.getAllEmp();
request.setAttribute("empList",empList);
%>
--套用数据源,使页面按照下拉数据源的形式显示;
<td>
<html:select property="deptId" value="${emp.deptId }" disabled="true">
<logic:iterate id="dept" name="deptList">
<html:option value="${dept.deptId}">${dept.deptName}</html:option>
</logic:iterate>
</html:select>
</td>
--说明:主要是给html:select添加了value属性,表示本数据的原始值,如:dept_id = 5;value="${emp.deptId }"
--配合使用html:select 和 logic:iterator,用logic:iterator取得数据,同时把数据放在html:opention中;
使用logic:iterator从后台获取数据;数据来源是页面中的java代码部分;
10.3 下拉数据源的二级联动
--思路:主要是通过在主下拉数据源内容变更的时候,去数据库中按照当前条件进行相关检索,同时把检索条件发送到页面,重新显示数据即可;
--具体配置过程:
10.3.1 jsp部分
10.3.1.1 在主数据源上配置变更事件
<html:select property="deptId" οnchange="f_getDorp()" value="<%=deptId %>">
<logic:iterate id="dept" name="deptList">
<html:option value="${dept.deptId}">${dept.deptName}</html:option>
</logic:iterate>
</html:select>
10.3.1.2 添加相应的javascripts
<script type="text/javascript">
function f_getDorp(){
//取得单位信息deptId;
var deptId = document.forms["empInputForm"].elements("deptId").value;
//alert("deptId="+deptId);
window.location = "office.do?action=getOfficeByDeptIdAction&deptId="+deptId;
}
</script>
10.3.1.3 调整页面中java代码
<%
//取得部门信息
String deptId = request.getParameter("deptId");
System.out.println("---deptId="+deptId);
OfficeInputAction officeInputAction = new OfficeInputAction();
OfficeAction officeAction = new OfficeAction();
List<OfficeInputForm> list = null;
if(deptId == null || deptId.equals("")){ //第一次使用
list = officeInputAction.getAllOffice();
request.setAttribute("officeList",list);
}else{
//用户调整内容
list = officeAction.getOfficeByDeptId(deptId);
request.setAttribute("officeList",list);
}
%>
10.3.1.4 配置下拉数据源的value值,保持页面刷新前的用户选择
<html:select property="deptId" οnchange="f_getDorp()" value="<%=deptId %>">
<logic:iterate id="dept" name="deptList">
<html:option value="${dept.deptId}">${dept.deptName}</html:option>
</logic:iterate>
</html:select>
--在html:select中添加了value="<%=deptId %>"
10.3.2 action部分
10.3.2.1 根据条件重新检索数据
public ActionForward getOfficeByDeptIdAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response){
this.printInfo("----getOfficeByDeptIdAction()");
String deptId = request.getParameter("deptId");
List<OfficeInputForm> list = getOfficeByDeptId(deptId); //调用子函数取得过滤数据;
this.printInfo("filterOfficeList.size()="+list.size());
request.setAttribute("officeList", list);
return mapping.findForward("filter");
}
11.struts事务管理
11.1 JDBC transaction
--主要思路:把conn连接属性赋值为:false,其余操作按照正常的sql进行逐步的执行,等到全部操作完成后进行统一的提交;
//取得连接
conn = ConnectOracleBase.getConnection(this.dbUser, this.dbPsw, this.dbServer);
//取消自动提交
conn.setAutoCommit(false);
...
ps.execute(); //执行第一句更新
...
ps.execute(); //执行第二句更新
//进行集中提交
conn.commit();
} catch (SQLException e) {
...
conn.rollback();
...
11.2 Hibernate事务
--主要思路:在执行操作前设置Transaction,执行相关操作,完成后执行提交tran.commit();,出现错误后执行 tran.rollback();
Session session = HibernateSessionFactory.getSession();
Transaction tran = session.beginTransaction();
try {
session.delete(userManager);
tran.commit();
} catch (HibernateException e) {
this.printError("delete user is error");
if(tran != null){
tran.rollback();
}
e.printStackTrace();
} finally{
session.close();
}
12. BeanUtils用法
/**
* BeanUtils用法:(本例实现目标:userManager->userForm)
* 1.import org.apache.commons.beanutils.BeanUtils;从后拷到前
* 拷贝顺序BeanUtils.copyProperties(dest,orig);
*
* 2.import org.springframework.beans.BeanUtils;从前拷贝到后;
* 拷贝顺序BeanUtils.copyProperties(source,target);
*/
//使用Apache的BeanUtils(从后拷到前)
//import org.apache.commons.beanutils.BeanUtils;
//BeanUtils.copyProperties(userForm,userManager );
//使用Spring的BeanUtils(从前拷贝到后)
//import org.apache.commons.beanutils.BeanUtils;
BeanUtils.copyProperties(userManager ,userForm);