分类: Java
2013-04-07 11:19:52
原文地址:struts2的一些知识概要 作者:雨天搁浅
struts2的处理流程:
(1)客户端发送一个请求,如*.action
(2)请求经过核心过滤器,过滤器将请求转发给相应的action代理
(3)action代理通过配置文件中的信息找到对应的action类,创建action对象并调用相应的方法
(4)在调用action前后会调用一些拦截器
(5)action执行完毕后,代理会根据配置文件找到execute返回字符串对应的结果
MVC的目的:使展现和业务相分离
优点:降低耦合性,提高程序的扩展性。各司其职,互不干涉。有利于分工。
1,在action中获取表单元素的值,最好的方法:
(1)不封装对象时,直接在action中定义各属性,然后提供get和set方法即可
(2)封装属性为javabean时,在action中定义某javabean所的在类的对象,然后提供get和set方法即可
注意:(a)javabean中的属性名字要和表单元素中的name属性的名字一样,否则难以得到值。
(b)action中要继承自ActionSupport类(该类中有很多方法可供使用)
2,在action中获取属性范围最好的方法是实现接口:ServletRequestAware,SessionAware,RequestAware,ApplicationAware(三个下面例子一样的)
如: Map
public void setSession(Map
session=arg0;
}
注意:得到原始的属性范围方法:
HttpServletRequest request=ServletActionContext.getRequest();
ServletContext application=ServletActionContext.getServletContext();
ServletContext application=request.getSession().getServletContext()
解耦得到属性范围:
Map request = ActionContext.getContext().getContextMap();
Map session = ActionContext.getContext().getSession();
Map application = ActionContext.getContext().getApplication();
3,重点struts2标签:得到表单的值,先放入值栈,在进入action,action中的所有属性都在值栈顶部存着,可直接去,从四种范围取值要加范围
(1)
(2)
例如是四种范围中的request,取出时用#request.键名
(3)
(4)
上面输出的是键(内容)=值(内容)
(5)令牌标签(token)用法:常用在登陆或注册里面防止重复提交
步骤:(a)在登陆或注册界面的form里面写
(b)在struts.xml配置文件中针对某个action进行拦截:
4,上传技术:
(1)上传界面中的表单:
(2)在action中定义三个变量,File uploadFile,String uploadFileContentType,String uploadFileFileName,
后俩个的前面部分和表单的name一定要相同。在获取get和set方法。具体如下: private File[] uploadFile;
private String[] uploadFileContentType;
private String[] uploadFileFileName;获取get和set方法略
//下面部分一般不再action中写,在业务逻辑biz中写,创建一个方法将uploadFile和uploadFileFileName传过去,
在写下面的东西,封装在调DAO
String path=ServletActionContext.getServletContext().getRealPath("/upload");
File file=new File(path);
if(!file.exists()){
file.mkdirs();
}
try {
if(uploadFile!=null){
for (int i = 0; i < uploadFile.length; i++) {
FileUtils.copyFile(uploadFile[i],new File(file,uploadFileFileName[i]));
}
return this.SUCCESS;
}
} catch (IOException e) {
e.printStackTrace();
}
return "fail";
设置上传文件大小有一个常量:struts.multipart.maxSize="2097152"默认是俩兆
(3)在上传时可能要判定个人要上传的文件的大小或者自己权限内的上传文件大小,可用下面方法处理:
String path=ServletActionContext.getServletContext().getRealPath("/upload")+用户名;
File myFile=new File(path);
File[] files=myFile.listFiles();得到文件夹下所有的文件
Long userSize=0已用空间的大小
for(File f:files){userSize+=f.length();}已用空间的大小计算
if(userType==1){根据权限算出自己剩余的空间大小
freeSize=32*1024*1024-userSize;
}else{
freeSize=128*1024*1024-userSize;
}
for(File f:uploadFiles){单个文件大小的限定
Long fileSize=f.length();
if(userType==1&&fileSize>1*1024*1024){throw new RuntimeException("普通用户单个文件最大为1M");}
else if(userType==2&&fileSize>2*1024*1024){throw new RuntimeException("VIP用户单个文件最大为2M");}
totalSize+=fileSize;
}
if(totalSize>5*1024*1024){throw new RuntimeException("总文件最大上传为5M,你超过了这个限度");}总文件大小的限制
else if(totalSize>freeSize){throw new RuntimeException("上传文件太大,存取空间不足");}
struts2运行异常的处理,在上述项目中用到
(a)在处理类里面抛出如上述的异常
(b)在struts.xml中:在包里面加全局的:
在action中局部的:
(c)在error.jsp页面:在要显示自己出错信息的地方加入struts2标签的一句话:
5,下载技术:
(1)在jsp界面传Id等,在action中定义Id和realpath,get,set方法,随意定义一个方法比如
public String ex(){
接收Id查数据库得到相对路径path,
realpath1=ServletActionContext.getServletContext().getRealPath("/upload")+“/”+path,
this.setRealpath(realpath1);
return "success";
}
(2)另一个方法固定:
public InputStream getInputStream(){
InputStream ips=null;
try {
ips=new FileInputStream(realpath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ips;
}
(3)配置文件:
application/actet-stream固定
inputStream(2)中方法名get后的东西
attachment;filename="${fileName}"数据库查的名字
4096缓冲的,可变
上面运行的步骤是:先根据通配符找到对应action的方法ex,执行完后,在自动执行getInputStream方法,完成下载
6,自定义类型转换器,最好的方法:
(a)定义类型转换器继承自StrutsTypeConverter(里面有俩个方法)
@Override
public Object convertFromString(Map arg0, String[] arg1, Class arg2) {
// TODO Auto-generated method stub
return null;
}
@Override
public String convertToString(Map arg0, Object arg1) {
// TODO Auto-generated method stub
return null;
}
(b)convertToString方法在这里没用,只在convertFromString方法中进行操作
String[] arg1中的arg1[0]是在表单中得到的要转换的东西的内容,要转换成什么就直接用字符串进行一般的
操作(如分割,格式化等),该封装封装,然后,返回自己所要的那个类型(c)全局转换(属性文件放在src下):
要加一个属性文件,文件名字命名为xwork-conversion.properties,里面是一个键值对,转换的那东西的全类名=转换器所在类
的全类名局部转换(属性文件放在和action同一个目录下):属性文件名字为action的类名-conversion.properties,
里面的键值对:属性名=转换器所在类的全类名
7,自定义拦截器:struts2内置了32个拦截器(动态网页转化为html的静态网页用到拦截器velocity,freemarker,模板技术)
(a)实现xwork的Interceptor接口,里面有三个方法destroy() ,init(), public String intercept(ActionInvocation arg0)
(b)在方法中得到session的方法:Map session = arg0.getInvocationContext().getSession();
return arg0.invoke():返回的这个值时拦截到的action中返回的那个值
(c)配置文件:
(1)自定义的拦截器放在
定义好后下面可以直接引用:若在action中只对action有效
(2)一般应用是,和defaultStack共同构成栈,然后在包里面默认,具体如下:
注意:(1)在配置中一般将登陆界面设置成全局结果视图,以便于非法时跳到登陆界面
(2)实现拦截器接口的类里面含有ActionContext,ActionServletContext,可以得到request,session等
8,数据校验:
报错input视图一般考虑俩方面问题:数据自动类型转换(action中接受jsp页面的值的转化)是否正确,数据校验格式是否正确
(1)validate()方法验证action中的所有方法,validateXXX,验证action中的XXX方法
校验失败时会调用addFieldError方法,跳到input视图,在视图中通过,
(2)上面的方法为原始方法,比较麻烦,下面是struts2封装好的校验方法;
配置文件:(a)和action在同一个包下,名字命名为action类名-validation.xml
其中xml中要想让其提示标签信息,要拷贝一个东西
(b)如果是封装的对象:xml名字的命名,
在action的目录下,action类名-封装的对象名(如user)-action中调用的方法名-validation.xml,内容为:
userContext
true
在封装的javabean目录下:xml名称,类名-userContext-validation.xml
里面内容的写法和不封装对象时一样
(c)在不封装对象时例如:
0
100
(3)常用的校验:required,requiredstring,stringlength(minLength,maxLength),email,double,visitor,regex等
9,国际化(i18n:internationalization)
(1)(a)java中的国际化提供了三个类,java.util.ResourceBundle(加载资源包),java.util.Locale(国家或地区对应的语言环境)java.text.MessageFormat格式化信息
(b)国家化的编写:在src下编写资源文件:命名方法为:随意(比如为mess)_zh_CN.properties
随意(和上面的要一样)_en_US.properties
在上面配置文件中可写键值对:如msg=你好{0},现在是{1}
java类里面写如下代码测试:
Locale locale=new Locale("zh","CN");
ResourceBundle bundle=ResourceBundle.getBundle("mess(对应上面的随意中的东西)",locale);
String msg1=bundle.getString("msg(对应配置文件中的键)")
输出MessageFormat.format(msg1,"wangshaowei(对应{0})",new Date()对应{1})
(2)struts2的国际化
(a)在struts.xml中指定资源文件的存储路径
(b)在页面引入struts的标签<%@ taglib uri="/struts-tags" prefix="s"%>
三种方法取出里面的值,我感觉最好的是
实际应用实例:
(a)写一个存国家信息的类,里面有一个方法
public Map
Map
Locale zh=Locale.CHINA;
Locale en=Locale.US;
locales.put("chinese",zh);
locales.put("english",en);
return locales;
}
(b)在src下:包名_en_US.properties(只针对包,局部的)
mess_en_US.properties(全局的)
(c)如果为全局的加一个常量
(d)在jsp页面里面的body中:
js部分: