struts2-第一天
框架搭建
1.jar包的准备
2.配置web.xml,配置struts2核心控制器,接收所有的请求(可在dispatcher.ng.filter包下拷贝,把.class去掉)。
3.拷贝struts.xml和log4j到src目录下。
3.1写个package包,给个名字:user,包就相当于一个模块,再添加extends="struts-default"
3.2里面写action标签,写name和实体类
3.3里面写result标签,写name和页面
执行的过程:请求url满足了/*,就交给了核心控制器,它启动会把struts.xml文件的配置全部读到内存中,用一个对象来保存,会在这
struts2-core-2.3.15.1.jar里org/apaqi/struts有配置文件default.properties,
1.更改请求后缀
2.开启开发模式
ActionSupport类
struts.xml里,
请求参数接收
一、标量值方式接收参数
struts对于提交到action的参数,会当作这个action有这个属性,就会调用这个参数set方法来接收(保存)提交的参数。
二、复合类型方式接收参数(常用)
三、模型驱动方式获取参数(少用)
1.业务逻辑控制器类要实现ModelDriven>接口
2.预先创建user,并提供方法返回user
3.代码不需要写getset方法
四、servlet API方式获取参数(需掌握)
1.业务逻辑控制器类要继承ActionSupport
2.通过ServletActionContext.getRequest()得到HttpServletRequest
3.就可以用以前getParameter()
Servlet APi 获取
一、ServletActionContext类(重点)
ServletActionContext.getRequest().getSession()
二、Struts2Aware拦截器IOC模式(重点)
1.实现ServletRequestAware接口,重写setServletRequest(HttpServletRequest request),把参数赋值给成员变量HttpServletRequest request,后面就可以使用request。
三、四、ActionContext类的get方法
Action动态方法
需要开启动态方法调用支持,
一、login!login.do叹号方式.注意:用感叹号动态调用时,配置文件的action是不写!的,在提交地址那里写,如不写!指定调用的方法,默认调用execute方法。
二、login_*统配
命名空间
1.命名空间前面加/
规则是:1.1如果命名空间存在,进入命名空间搜索action,action存在就执行,不存在就报异常
1.2如果命名空间不存在,自动删除最后的命名空间,再进行搜索
2.加命名空间后,提交地址要加前面那段(不能/开头),设置了后缀加后缀,但配置那里的action的name属性不加后缀(这里必须注意)。
3.当配置文件struts.xml的
六、类型转换
2013-1-15默认会转换?月份有0吗?
自定义类型转换器的实现
方式1.继承DefaultTypeConverter类
1.1如上,UserAction类要继承ActionSupport类(如不继承,无法显示异常等)
1.2重写convertValue方法
1.3在action包下新建一个同名的UserAction-conversion.properties,文件内容:user.loginTime属性 = org.fkjava.converter.MyConverter转换器
全局的跟struts.xml配置文件放在一起
方式2.继承StrutsTypeConverter类(抽象类)(推荐使用)
--有两个要实现的方法,主要实现前台到后台convertFromString(Map context,String[] values,Class toType)方法,第一个参数是上下文,第二个是提交的实际数据,第三个是提交数据的类型
方法实现逻辑:判断values不为空后,如果写的是转换时间的转换器,判断toType==Date.class,一旦涉及到时间对象,simpleDateFormat,从字符串转换为Date类型用sdf.parse(values[0])
全局:在src下xwork-conversion.properties,java类型=自定义转换器
转换错误显示:
1.默认:
1.1<%@taglib prefix="s" uri="/struts-tags"%>,
2.局部类型转换失败自定义信息
2.1在action包下新建一个UserAction.properties文件,内容是invalid.fieldvalue.属性名(表单提交的name属性user.loginTime)=提示语句
2.2throw new TypeConstraintException("日期类型转换失败!");
3.全局类型转换失败自定义信息
3.1 src根目录下,fkjava.properties国际化资源文件:xwork.default.invalid.fieldvalue={0},提示信息
3.2 struts.xml下配置常量name="struts.custom.i18n.resources" value="fkjava"/>
七、后台验证
如果希望使用struts2提供的验证框架,必须extends ActionSupport
调用步骤:
1.先类型转换
2.验证
3.调用目标action方法
方式一:代码方式实现输入验证
a.对action所有方法进行验证
方式1:重写ActionSupport中的validate方法
//针对本action的所有action方法进行验证
public void validate(){
System.out.println("-------validate()--------");
if(user == null || "".equals(user.getUserName())){
/**一旦addFieldError()加了东西,就会返回INPUT*/
this.addFieldError("user.userName","请输入用户名");
}
}
--输出错误信息:
b.对单个方法进行验证,只需要在这个方法的后面加你要验证的方法,如login方法要验证,validateLogin()
方式二:配置xml方式实现输入验证(比较常用)
xml文件名写法:NoticeAction-addNotice-validation.xml针对一个action请求做后台验证(中间是
NoticeAction-validation.xml针对整个NoticeAction处理类都做后台验证
例子:
"http://struts.apache.org/dtds/xwork-validator-1.0.dtd">
true
4
6
国际化
表单:
1.写fkjava.properties国际化文件,依次再写其他语言的properties。说明:里面写的就是需要替换的字眼
2.用struts2标签库写表单(先引入),表单里的每一项多一项key的属性,写的就是properties里面的key
3.如果想动态改变语言环境,加一个带request_locale参数的表单,如直接提交到jsp不行,就配置一个最简单的action把表单提交到action,再
页面:
1.使用i18n标签,name=资源文件前缀,
代码中:
1.put之后,利用ActionContext.getContext.put("msgs",this.getText("国际化资源里的key")),页面上取出:${msgs}
result的type属性
服务器重定向
1.dispatcher(默认),转到资源(jsp html 其他视图技术)
2.chain,转到一个action,参数有actionName,nameSpace,method等。
客户端重定向(参数不会自动传递,如需传递,在actionName拼接,或加123456)
动态跳转:定义动态结果页面(如果登录名等于tom,跳到tom.html)定义成员变量typePath,并提供getset方法
全局result
1.包里配置
2.如果局部全局都有,局部起作用。
异常处理
1.局部
2.全局
注意:当局部异常处理找不到才会找全局
3.异常信息显示
方式一:引用struts标签库,
方式二:直接EL表达式:${exception.message}和${exceptionStack}
拦截器
自定义拦截器
1.写一个类继承AbstractInterceptor,重写intercept方法。
2.invocation.invoke()把控制权限交给下一个拦截器,没有的话交给action,返回值String就是提交给action执行的方法执行完以后返回的字符串
3.配置拦截器在package里,引用(使用)是在action里。
4.一旦自定了拦截器,默认的就不起作用。
5.拦截器的定义顺序决定了调用的顺序,最好先配置好默认的拦截器
6.如果有一堆的拦截器要用,可以配置一个拦截器栈
7.如果在一个package中不想每一个action都写引用拦截器,可以在package里定义默认拦截器
方法拦截器
1.写一个类继承MethodFilterIntercepter,重写doIntercept方法。
2.引用时多一项参数login,logout,指定哪些会调用拦截器(白名单)
3.如果白名单和黑名单冲突,白取胜(邪不压正)。
内置拦截器
timer:统计action方法执行耗时的拦截器
token:防止表单重复提交
1.在表单提交的action上调用默认拦截器
2.配置当出现重复提交时到什么页面
3.页面上用struts标签库,在form里加上
登录检查
1.自定义一个拦截器
String result = "login";
if(flag){
HttpSession session = ServletActionContext.getRequest().getSession();
User u = (User)session.getAttribute("loginUser");
if(u != null){
result = invocation.invoke();
}
}else{
result = invocation.invoke();
}
return result;
2.配置(声明)拦截器
3.调用拦截器(先调用系统默认),里面还可以给拦截器参数(拦截器的成员变量要有getset方法)
freemarker
使用要引入一个jar包和要在web.xml文件中做一个配置。
文件上传下载(注意这里:配置跟default.properties有关!)开始是在struts2-core-2.3.15.1.jar这个jar文件里的
一、单个文件上传
上传的form表单的method属性必须是post,enctype必须是multipart/form-data
1.页面的表单
这时要配置action:
注意这里action配置没有命名空间,如果有,表单提交action要加命名空间。??
2.UserAction里
2.1增加属性
private File headImg;//接收文件用的属性(可以跟表单的不一致,因调的是set方法)
private String headImgFileName;
private String headImgContentType;
//三个属性要增加getset方法
说明:这样写才能获取到文件名和文件类型
2.2.upload方法里
//获取服务器的资源(存储)路径
String path = ServletActionContext.getServletContext().getRealPath("p_w_picpaths");
File file = new File(path,headImgFileName);
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
FileUtils.copyFile(headImg, file);
2.3如想方便查看上传的文件,可设置上传路径:双击tomcat,在ServerLocations那里,
选中间那一栏(使用tomcat安装路径)。
二、多个文件上传
属性改为数组,循环new File,其他基本不用变。
上传约束配置
1.全局大小限制:struts.xml里,配置整个工程:
2.局部大小限制:局部的大小限制必须小于全局大小限制!在对应的action下配置
数值
注意点:建议把默认的拦截器放在上传约束拦截器下面。
3.类型约束:p_w_picpath/pjpeg,p_w_picpath/x-png
4.后缀约束:.jpg,.png,.bmp
三、下载
1.struts-user.xml文件配置下载的action:
application/octet-stream
fileStream(要与Action类getset方法对应)
p_w_upload;filename="${fileName}"//对应action类fileName属性get方法
2.在UserAction类增加getFileStream方法
public InputStream getFileStream(){
return ServletActionContext.getServletContext().getResourceAsStream("/p_w_picpaths/"+fileName);
}
还要增加fileName属性,提供getset方法,在页面上增加这个参数。
3.中文乱码:在取流的方法里,return之前加上这句(getResource里的变量毫无疑问改成s):
String s = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
4.下载页面:
OGNL表达式
值栈(valueStack):取值栈里的值:${user.userName}或者
栈(stack)中获取数据要加#号:
访问对象属性中还是对象:
访问方法:调用值栈中对象的普通方法:
开启允许静态方法调用:
取值栈的一个例子:
Struts2标签
1.控制标签
1.1-iterator标签操作Map:
方式一:操作简单的Map:
value是json数据,var是临时变量,显示用
方式二:后台准备数据,
Map
Map
maps.put("A","中国");
maps.put("B","美国");
maps.put("C","英国");
request.put("maps",maps);
页面:value="#request.maps",其他不变
1.2—iterator标签操作List:
方式一:这时value不用#号{'a','b','c'},显示就去掉.key和.value,其他一样。
方式二:List
userList.add(new User("admin",12,new Date()));
userList.add(new User("admin2",13,new Date()));
request.put("userList",userList);
页面:value="#request.userList" var="l",显示
iterator标签进行数据过滤操作
?获取满足条件的所有数据
value="#request.userList.{?#this.userPass %2 != 0}"//意思是判断当前迭代对象的userPass与2取余不为0就输出
^获取满足条件的第一条数据
value="#request.userList.{^#this.userPass %2 != 0}"
$获取满足条件的最后一条数据
value="#request.userList.{$#this.userPass %2 != 0}"
if...else if...else
输出语句
输出语句
输出语句
append集合合并标签:把两个list拼接在一起放在newList里
generator字符串分割标签:分割完是一个数组g
subset获取子集合
方式一:在里面迭代
方式二:在其他地方迭代
2.数据标签
set标签:指定把某值用var的变量名字设置到某个范围
push标签:将某个值置于值栈的顶部,标签结束后,将从值栈中移除。
bean标签:可以在页面创建一个对象
date标签:
<%
request.setAttribute("now",new java.util.Date());
%>
include标签
================================
4、struts2的处理流程
a、browser-->struts2控制器-->查找action(在配置文件找)-->(回到)struts2控制器-->拦截器1,2,3...-->动作Action-->(request)struts2控制器-->查找视图(配置文件找)-->struts2控制器-->视图-->browser
一个请求在Struts2框架中的处理大概分为以下几个步骤
1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求
2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin)
3 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action
4 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy
5 ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
6 ActionProxy创建一个ActionInvocation的实例。
7 ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
8 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可 能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper
在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。
5、Struts2配置文件
a、可以给每个模块定义一个包(Package元素的namesapce属性)
b、继承某个package(Package元素的extends属性)
c、为了让大型应用的struts.xml更好管理,可以把它分成几个较小的文件ps:
6、拦截器是什么?struts-default.xml
是将控制器不做的事情封装在另外一个地方
a标签路径最好是通过绝对路径来:request.getContextPath()
接收参数三种方式:
1.Action属性来接收
2.用VO来封装表单属性
3.利用ModelDriven模型驱动来接收
要实现 implements ModelDriven
==========填充下拉列表==========
第一种:
第二种:
先定义private List
第三种:
$.ajax({
url : "${ctx}/dept/loadDeptAjax.action",
type:"post",
dataType:"json",
async : true,
success:function(data){
//获取选中的
var deptId = "${employee.dept.id}";
alert();
$.each(data,function(){
$("").val(this.id).text(this.name).attr("selected",this.id == deptId).appendTo("#deptSelect");
});
}
});
List
========================Struts2========================
namespace
1、命名空间一般是以“/”开头
2.当namespace=""时,它会匹配所有的。
request.getScheme()+request.getServletName()+request.getServletPort()+path;
动态方法调用(DMI):
意思就是不配置method属性,在请求的时候这样:user!add
参数接收:
1.普通类型
2.用DTO来接收
public class UserDTO{
private String name;
private String pwd;
private String cpwd;
}
3.模型驱动:
public class UserAction implements ModelDriven
private User user = new User();
public String add(){
return SUCCESS;
}
public User getModel(){
return user;
}
}
参数校验:
addFieldError("name","name is error!");
页面:
(Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
在页面上拿,要用#key这种方式。
Result的配置
forward到另外一个action
全局result
动态结果集
遍历操作:
遍历过的总数:
遍历的元素索引
当前是偶数:
当前是奇数:
是第一个元素吗:
是最后一个元素吗:
遍历map
struts2错误标签自动有样式:
可以.fielderror ul li{ list-style-type:none; }解决
struts2Filter -> 拦截器 -> xxAction
↓
struts2Filter <- 拦截器 <- xxAction
默认拦截器都配置在struts-default.xml
拦截器也是配置在struts.xml文件里,