Struts2的复习
开发struts2所需要的包
Struts2的启动配置
Struts2的配置文件是放在src的目录下,但是struts1的配置文件是放在WEB-INF的目录下
Struts2的struts.xml文件
<struts>
<!-- 这是 package里面有一个属性abstract如果设置为true,那么它下面不允许再写action-->
<!--name是为每个action取一个唯一的名字(因为可能下面有action需要继承它),千万记得namespace必须以’/‘开头, 但是name不需要,class是action的类名,method是处理请求的方法,来访问这个action的路径是namespace + action的name 即:/go/test -->
<package name="firstAction" extends="struts-default"namespace="/go">
<action name="test"class="com.actions.FirstAction"method="getFirstAction">
<result name="success">/WEB-INF/page/success.jsp</result>
</action>
</package>
</struts>
启动struts2的web.xml里面的过滤器
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<!--org.apache.struts2.dispatcher.FilterDispatcher这是2.13以前的版本-->
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
解决struts.xml文件里没有提示的问题?
首先window-->Preferences然后在文本框中打xml查找,看到的下拉里表下找到xml catalog点击右边的add然后在弹出的文本框中,在location寻找struts-2.0.dtd的文件, key Type选uri,在key中写上http://struts.apache.org/dtds/struts-2.0.dtd这是在struts.xml的配置文件中中有这句代码。
Action名称的搜索顺序
举一个例子:
Struts2的默认访问后缀是以.action结束的。
假如你的url = "http://127.0.0.1:8080/firstStruts/go1/go2/go3/test";首先是去查找/go1/go2/go3结束的,如果不存在就去查找/go1/go2如果还找不到就去找/go1还找不到,就去找找默认的package,然后到默认的包里面去查找那个action如果找不到页面就会报炸不到action的错误!
不懂仔细看上序的那张图
<struts>
<!-- 这是 package里面有一个属性abstract如果设置为true,那么它下面不允许再写action-->
<!--name是为每个action取一个唯一的名字(因为可能下面有action需要继承它),千万记得namespace必须以’/‘开头, 但是name不需要,class是action的类名,method是处理请求的方法,来访问这个action的路径是namespace + action的name 即:/go/test -->
<package name="firstAction" extends="struts-default"namespace="/go">
</package>
<!-- 默认的命名空间就是不设置namespace或者设置namespace="" -->
<packagename="it"extends="struts-default">
<actionname="test"class="com.actions.FirstAction"method="getFirstAction">
<result name="success">/WEB-INF/page/success.jsp</result>
</action>
</package>
</struts>
Action配置中的一些默认项
<!--action中的class默认值是com.opensymphony.xwork2.ActionSupport, method的默认方法是execute,result中的name的默认值是success,在execute方法中默认返回的值是seccess -->
<package name="secondPackage"extends="struts-default"namespace="/secondRequest">
<action name="firstAction">
<result>/WEB-INF/page/addUser.jsp</result>
</action>
</package>
Action中的result的各种转发类型
Dispatcher(这个相等于转发,也是默认的)、redirect(这个是重定向)、redirectAction、plainText
<package name="thirdPackage"extends="struts-default"namespace="/thirdRequest">
<action name="secondAction"class="com.actions.FirstAction"method="getFirstAction">
<!-- 就算是redirect,重定向的页面也必须以'/'开头 ,这是往地址栏中传递参数,参数就是在action中的一个属性的值-->
<result name="success"type="redirect">/success.jsp?userName=${userName}</result>
</action>
</package>
页面需要进行解码
<%
//因为传递过来的是经过编码后的汉字,所以必须解码才能够进行输出,否则会出现乱码
%>
${param.userName }
//这是action进行的编码
userName = URLEncoder.encode("曹欢","utf-8");
//这是解码的类URLDecoder
<%=URLDecoder.decode(new String(request.getParameter("userName").getBytes("iso8859-1"),"utf-8"),"utf-8")
//因为是重定向,所以不能得到保存在request作用域的值
//${userName };
%>
关于dispatcher、redirect、redirectAction、plainText这四个属性,有很多知识,视屏是struts2的第六个,在struts中也有这个例子。(这个例子里面讲了很多东西,有很多细节啊)
<action name="injectFirstAction"class="com.actions.RegistAction"method="execute">
<!-- 这是为action的某个属性注入值 -->
<paramname="injectMessage">我的名字叫曹欢</param>
<resultname="success">
/success.jsp
</result>
</action>
Struts中的常量
在struts2中配置常量的,可以再struts-default、struts-plugin.xml、struts.xml、struts.properties、web.xml中配置常量,但是如果配置常量重复的话,那么后面的配置文件中的相同的常量会覆盖前面配置的常量。
一些常用的常量的配置
<!--这是控制request的编码 -->
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<!--这是修改struts2的访问路劲的修改,如果要有几种方式,则value ="do, action" -->
<constant name="struts.action.extension" value="do"></constant>
<!--这是浏览器是否包村静态页面的缓存 -->
<constant name="struts.server.static.browserCache" value="false"></constant>
<!-- 这是修改配置文件后是否自动读取配置文件 -->
<constant name="struts.configuration.xml.reload" value="true"></constant>
<!-- 开发模式下可以打印更多的错误性信息 -->
<constant name="struts.devMode" value="true"></constant>
<!-- 这是关于默认的试图主题 -->
<constant name="struts.ui.theme" value="simple"></constant>
<!-- 这是有spring来管理action --><!--注意这要在加载spring与struts2的包时才可以使用 -->
<constant name="struts.objectFactory" value="spring"></constant>
<!-- 这是动态的struts2是否支持动态调用 -->
<constant name="struts.enable.DynamicMethodInvocation" value="false"></constant>
<!-- 这是文件上传的大小的指定,是所有的文件大小的指定,如果是几个文件,只得是几个文件的大小加起来的大小 -->
<constant name="struts.multipart.maxSize" value="10701096"></constant>
<!--定义全局范围的资源文件-->
<constant name="struts.custom.i18n.resources" value="基名"></constant>
Struts的流程图
Struts2与struts1的最大不同就是它的每个请求就会创建一个action,就是线程安全的,但是struts1是单实例是线程不安全的。Struts1创建了一个action然后把它保存在内存中,每次访问都是拿出内存的那个action
<includefile="这里填写配置文件的名字"></include>
Action的动态方法的调用
假如你系那个进入action的某个方法,可以再地址栏中
http://127.0.0.1:8080/struts2-2/injectAction/injectFirstAction!execute.action这样你进入的就是execute方法
但是这种方式struts2的文档已经建议不使用,可能在以后的版本中就会取消
但是如果你加上一个常量的设置,这种 方式就不能使用
<!-- 如果设置为false,这是禁止动态方法的调用 -->
<constant name="struts.enable.DynamicMethodInvocation"value="false"></constant>
也可以采用通配符来进入到action的某个方法
<!-- 使用通配符来判断进入到action的哪个方法 -->
<packagename="injectPackage"extends="struts-default"namespace="/injectAction">
<!-- 这里的action的name使用了通配符,表示的就是进入到action的通配符的那个方法里面,后面的method就指名了,第一个通配符就用{1}来表示,因为通配符可以使用几个啊!在下面的class、result的值中都可以使用通配符 -->
<!-- 只要在访问的路径中的injectFirstAction_add表示的就是进入到add方法中 -->
<actionname="injectFirstAction_*"class="com.actions.RegistAction"method="{1}">
<!-- 这是为action注入值 -->
<paramname="injectMessage">我的名字叫曹欢</param>
<resultname="success">
/success.jsp
</result>
</action>
</package>
页面:
表示的是进入到add方法中
<ahref="${pageContext.request.contextPath}/injectAction/injectFirstAction_add.action">click</a>
Action接收请求参数
这是关于请求参数的接收,在struts2中有这个例子
假如页面有一个关于生日的文本框,它写的格式是1990/09/09这样在action就不能这样接收,
这时候就需要一个转换器,局部转换器只能对该包下的类中的属性进行转换。
定义局部转换器的步骤:1、首先些一个转换器的类。需要继承一个转换器的类。需要实现它的convertValue的方法。
public class DateConvertextends DefaultTypeConverter{
//第一个参数是关于ongl的一个上下文, value是传进来的目标值,toType是要转换成的类型
public Object convertValue(Map<String, Object> context, Object value,
Class toType) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
System.out.println("asdasd");
System.out.println(toType);
if(toType == Date.class)
{
String [] s = (String [])value;
String s1 = s[0];
try {
return simpleDateFormat.parse(s1);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(toType == String.class)
{
System.out.println("caohuan");
Date date = (Date)value;
System.out.println(date);
return simpleDateFormat.format(date);
}
else
{
return null;
}
return null;
}
}
2、然后对要转换的那个action中的某个属性进行配置。在要转换的那个属性的action的包下写一个类名-conversion.properties的文件。然后对要转化的属性进行配置:birthday = 转换器的类全名。请看struts2的这个例子
全局转换器与局部转换器的不同:
1、需要把转换器的配置文件放在src的目录下。
2、需要配置文件中的那个转换的类型改成具体的类型:如;如果你是转换date类型的数据:java.util.Date = 转换器的类全名。
3、需要把配置文件的名字改为xwork-conversion.properties
怎样在action的方法的各个作用域中添加属相,主要是ActionContext这个类
ActionContext actionContext = ActionContext.getContext();
actionContext.put("a","这是request作用域的范围");
actionContext.getSession().put("b","这是session范围的作用域");
actionContext.getApplication().put("c","这是application范围的作用域");
如果我非要等到各个作用域怎么办?
//这是得到request
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("caohuan","1111");
HttpSession
//这是得到session
session = ServletActionContext.getRequest().getSession();
session.setAttribute("huangwentao","222");
//这是得到servletContext对象
ServletContext context = ServletActionContext.getServletContext();
context.setAttribute("xiaohua","333");
一个小的知识点:actionContext.put("arr", Arrays.asList("go1","go2","go3"));这是王request对象中存储集合list
单文件上传
有这个例子的详细代码
一个细节:在IE6中的文件上传中可以自己书写地址,但是在IE的后面版本不可以,在其他的浏览器里面不可以写。
也有多文件上传的例子
这里也有文件下载的例子,特别经典。
对action的方法进行校验
手工书写对所有的action方法进行校验
1、action需要继承ActionSupport,然后重写validate方法
public void validate() {
if(userName ==null ||"".equals(userName.trim()))
{
//这是将错误保存起来
this.addFieldError("userNameError", "用户名不能为空");
}
if(mobile ==null ||"".equals(mobile.trim()))
{
this.addFieldError("mobileError", "电话号码不能为空");
}else
{
//这是匹配器匹配电话号码
if(!Pattern.compile("^1[358][0-9]{9}$").matcher(this.mobile).matches())
{
this.addFieldError("mobileError", "电话号码书写不正确");
}
}
}
2、如果出现表单验证错误,需要跑到错误页面,需要配置input
<package name="firstPackage"extends="struts-default"namespace="/test">
<action name="validate_*"class="com.actions.ValidateAction"method="{1}">
<result name="success">/success.jsp</result>
<!-- 这里的input表示的是如果验证出现错误就跑到错误页面 -->
<result name="input">/index.jsp</result>
</action>
</package>
3、在页面显示错误,用<s:filedError>来显示错误
<formaction="${pageContext.request.contextPath}/test/validate_update.action"method="post">
<inputtype="text"name="userName"/><s:fielderror fieldName="userNameError"/><br/>
<inputtype="text"name="mobile"/><s:fielderror fieldName="mobileError"/><br/>
<inputtype="submit"value="提交"/>
</form>
对action的制定方法进行校验
对action中的某个方法进行校验(手写的代码)只需要在对action中的所有的方法进行校验的基础上在validate的后面加上要校验的方法名。记得方法名的第一个字母要大写
//这是对action的所有方法全部进行校验,如果在validate的后面加上方法的名字,那么就只对action的这个方法进行验证,记得方法名的第一个字母要大写
public voidvalidateUpdate() {
if(userName ==null ||"".equals(userName.trim()))
{
this.addFieldError("userNameError","用户名不能为空");
}
if(mobile ==null ||"".equals(mobile.trim()))
{
this.addFieldError("mobileError","电话号码不能为空");
}else
{
//这是匹配器
if(!Pattern.compile("^1[358][0-9]{9}$").matcher(this.mobile).matches())
{
this.addFieldError("mobileError","电话号码书写不正确");
}
}
}
校验器的流程
系统有一个fieldErrors,
首先页面的form表单的字段传递进来(是通过类型转换器进行转换的),如果在转换的过程中出现错误(也就是有的字段不能转换),那么就会把转换错误保存到fieldErrors中,不管是否转换正确,都会进行下列步骤。
然后进入到要校验的方法,首先进入的是校验action某个方法的校验器,然后再进入到校验action中所有方法的校验器。如果在这个过程中出现错误,那么就会跑到input指向的错误页面,如果没有出现错误就会跑到result指向的页面。------>在这个过程中一定得注意,因为当类型转换器出现错误的时候也会将错误保存到fieldErrors中,所有即使在后面的校验器中没有出现错误,也会跑到input指定的页面。
基于xml对action中所有的方法进行校验
收先是写一个配置文件,名字就是这个类的类名+validation.xml, 然后在xml文件中配置一些校验器(系统写了很多校验器),这些校验器在<!-- 这是struts的校验器,这些校验器在xwork-core的com.opensymphony.xwork2.validator.validators包下的default.xml有很多校验器,可以自己去看看 -->至于xml文件中的具体可以参看这个例子
<validators>
<fieldname="userName">
<field-validatortype="requiredstring">
<paramname="trim">true</param><!-- 这个设置是默认的 -->
<message>You must enter a name</message>
</field-validator>
</field>
<fieldname="mobile">
<!-- 这是struts的校验器,这些校验器在xwork-core的com.opensymphony.xwork2.validator.validators包下的default.xml有很多校验器,可以自己去看看 -->
<field-validatortype="requiredstring">
<paramname="trim">true</param>
<message>you must enter a mobile</message>
</field-validator>
<field-validatortype="regex">
<paramname="trim">true</param>
<paramname="expression"><![CDATA[^1[358]\d{9}$]]></param>
<message>you must enter a legal mobile</message>
</field-validator>
</field>
</validators>
如果在校验的xml文件中没有提示咋办
关于校验器
校验器visitor的用法
visitor校验器是校验Action中的复合类型属性。
1.定义UserInfo.java
public class UserInfo {
private String name;
private String location;
注:有以上两个属性的get/set方法。
}
2.Action定义:
private UserInfo user;
注:Action中有user的get/set方法。
3.JSP写法:
<s:textfield name="user.name"></s:textfield>
4.校验文件配置:
1>.基本校验文件:
<field name="user">
< field-validator type="visitor">
< param name="context">userContext</param>
< param name="appendPrefix">true</param>
< message>测试:</message>
< /field-validator>
</field>
2>.复合类型校验文件:
<field name="name">
< field-validator type="requiredstring">
< message>姓名必须输入!</message>
< /field-validator>
</field>
<field name="location">
< field-validator type="requiredstring">
< message>籍贯必须输入!</message>
< /field-validator>
</field>
注:1>.复合类型校验文件命名:UserInfo-userContext-validation.xml
2>.复合类型校验文件位置同UserInfo.java在同一目录下。
用xml对action中的某个方法进行验证
Xml对action中某个方法进行校验值需要在上序的基础上将配置文件改一下。Action的类名-action的某个方法-validation.xml action的某个方法指的是struts中的action的name属性,只不过要把*改为具体的方法名。有这个例子
Xml校验的特点
好好看一下,关于校验的很多特点,值得学习。
总结:不管你是用手写代码的方法验证还是用xml验证,总之验证的action一定得继承actionSupport
全局范围的国际化
Action必须继承actionSupport
首先写两个国际化的资源文件
然后在再struts.xml文件中读取国际化资源文件,value是国际化资源文件的基名
<constantname="struts.custom.i18n.resources"value="itcast"></constant>
在页面里面读取资源文件里面的内容:<s:textname="go"></s:text>name是国际化资源文件里面的键值对的键。
在action里面读取资源文件里面的值System.out.println(this.getText(go));
go是国际化资源文件里面的键
输出带有占位符的国际化资源文件
如果页面要输出的话:
<s:text name="go">
<s:param>caohuan</s:param>
<s:param>study</s:param>
</s:text>
如果是action中要出入值的话:字符窜数组是往国际化资源信息里面填充值
this.getText("go",new String[]{"caohuan","study"})
在包范围的国际化资源信息
就是在action的包下配置国际化资源文件,package_语言_国家
如果只是读取包下的国际化资源文件里面的内容,那么不需要
<constantname="struts.custom.i18n.resources"value="itcast"></constant>这句代码也可以读取的到,但是如果在包下的资源文件里面读取不到信息,就会跑到全局范围的国际化资源文件里面读取内容,但是像在index.jsp是读取不到包下的国际化资源文件里面的内容的,所以必须读取全局范围国际化资源文件里面的内容
Action范围的资源文件
就是在actionl类的写上action的资源文件,命名规则:类的名字_语言_国家
TestAction_zh_CN.properties
不进行任何配置,直接读取配置文件下的资源文件
<!-- 这是从全局范围内读取国际化资源文件,在struts.xml的配置文件里面可以不写<constant name="struts.custom.i18n.resources" value="itcast"></constant>这句代码 -->
<s:i18nname="itcast">
<s:textname="go">
<s:param>caohuan</s:param>
<s:param>study</s:param>
</s:text>
</s:i18n><br/>
<!-- 这是从包中读取国际化资源信息 -->
<s:i18nname="com/actions/package">
<s:textname="go">
<s:param>caohuan</s:param>
<s:param>study</s:param>
</s:text>
</s:i18n><br/>
<!-- 这是从action中读取国际化资源信息 -->
<s:i18nname="com/actions/TestAction">
<s:textname="go">
<s:param>caohuan</s:param>
<s:param>study</s:param>
</s:text>
</s:i18n>
Ognl表达式,可以好好看看ognl的那个视频。里面的东西很重要,重要的是要懂得原理
标签
Property属性
Iterator标签
<s:set>标签
<s:url>标签
<s:checkBoxList>标签
<s:radio>标签
<s:select>标签
防止表单重复提交
Ssh2整合所需要的包:
枚举类型的映射
Ssh2的整合其实也很简单,hibernate与spring的整合与以前一样,只不过当spring管理action的时候用的是<constant name="struts.objectFactory" value="spring"></constant>
<constant name="struts.action.extension"value="do,action"></constant>
<constant name="struts.objectFactory"value="spring"></constant>
<packagename="caohuan"extends="struts-default"namespace="/test">
<!-- 下面的class是在spring中实例化的action的名字 -->
<actionname="go_*"class="testAction"method="{1}">
<result name="success">/success.jsp</result>
</action>
</package>可以看这个例子
浪溪的那套视频的讲解笔记
1、怎么将我们的struts2的源文件编程我们的css/html格式的帮助文档?
因为我们的struts2没有css/html格式的帮助文档?
首先将建一个javaProject,然后将虽有的.java的文件复制到src下(这些java文件就是我们struts的核心库的源文件,我的电脑的路径:D:\终极复习版\struts\struts2的综合\struts2的一些包\struts-2.3.1.2-all\struts-2.3.1.2\src\core\src\main\java),这里会出现没有导入包的错误,然后将所有的struts2依赖的包导入进去,然后点击prohect的菜单---->generate javadoc---->然后进入到下面的页面,注意下面的选中部分,一定要是我们的jdk的bin文件下的javadoc.exe
Destination是将我们的文件导入到那个文件
Document title是文档的名字,选中所有的文件,然后点击下一步下一步就可以完成了
2、类型转换的讲解
Struts2对于八种基本类型及常用的string、date类型这行都是能够用struts内部的转换机制自动转换的,但是对于对象等复杂的类型就不能自动转换了,需要自己定义方式了。
上面的讲解中有详细的讲解