Struts2简述
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。
javaWeb中的三层架构 :
表现层:MVC,struts2框架其实是对表现层的MVC作了优化
控制层:service
持久层:dao
Struts2 基本配置
导入基本包
Struts2中jar包有很多,但我们不需要导入全部只需要导入一些基本的即可。
配置web.xml
<filter>
<filter-name>action2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>action2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
配置核心配置文件struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<package name="demo" extends="struts-default" namespace="/">
<action name="loginAction" class="ynk.itcast.action.CheckAction">
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
package:可以为任意值
extends:固定struts-default,也可以继承自己写的包名
namespace:默认为/,可不写
配置文件中常用的常量
struts.i18n.encoding:该常量指定struts2应用默认使用的字符集。
struts.objectFactory.spring.autoWire:和spring框架整合有关。
struts.multipart.parser:指定文件上传用的组件。默认为jakarta(即common-fileupload上传组件)
struts.multipart.saveDir:指定上传文件的临时保存路径
struts.multipart.maxSize:指定上传中整个请求所允许上传的最大字节数。
struts.action.extension:指定struts2需要处理的请求后缀。默认值为.action或者什么都不写
struts.serve.static.browserCache:设置浏览器是否缓存静态内容,当应用处于开发阶段时,我们希望不缓存,可设置为false
struts.enable.DynamicMethodInvocation:设置struts2是否支持动态方法调用,默认值为true
struts.devMode:设置struts2是否使用开发模式。如果设置为true,为开发模式,修改struts.xml配置文件不需要重启服务器,会显示更多更友好的错误提示。
struts.ui.theme:指定视图主题。
struts.url.includeParams:指定struts2生成url时是否包含请求参数。有none,get和all三个值。分别对应不包含,仅包含get类型请求参数和包含全部请求参数。
常量修改
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
result标签中的type属性
1.chain:用来处理Action链,被跳转的action中仍能获取上个页面的值,如request信息。
2.dispatcher:用来转向页面,通常处理JSP(默认)
3.freemaker:处理FreeMarker模板
4.httpheader:控制特殊HTTP行为的结果类型
5.stream:向浏览器发送InputSream对象,用来处理文件下载,还可用于返回AJAX数据
6.velocity :处理Velocity模板
7.xsl: 处理XML/XLST模板
8.plainText:显示原始文件内容,例如文件源代码
9.plaintext:显示原始文件内容,例如文件源代码
10.redirect:重定向到一个URL ,被跳转的页面中丢失传递的信息,如request
11.redirectAction :重定向到一个Action ,跳转的页面中丢失传递的信息,如request
Action的方法调用
创建Action只需要继承ActionSupport类即可
method属性调用
<action name="loginAction" class="ynk.itcast.action.CheckAction" method="Login">
<result name="success">/index.jsp</result>
</action>
执行Action时会调用method里的属性值方法,如果不填method属性,则默认调用execute()方法
使用通配符动态调用
<action name="*_Action" class="ynk.itcast.action.CheckAction"method="{1}">
<result name="success">/welcome.jsp</result>
<result name="input">/regist.jsp</result>
</action>
method中的{1}的值为第一个*匹配到的值,此action可匹配任何以 _Action 结尾的action
定义全局视图
<global-results>
<result name="mainpage">/main.jsp</result>
</global-results>
即无论是哪个action,只要返回的是mainpage都跳转到main.jsp页面
分文件编写配置文件
struts2可以将一个配置文件分解成多个配置文件,从而进行模块化的设计,也提高了配置文件的可读性。
将不同的模块写在不同的配置文件中
<struts>
<include file="struts-student.xml"/>
<include file="struts-teacher.xml"/>
.......
</struts>
Struts2 数据封装
属性封装传递
action中
private String username;
private String userpassword;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserpassword() {
return userpassword;
}
public void setUserpassword(String userpassword) {
this.userpassword = userpassword;
}
jsp中
<form action="test">
用户名:<input type="text" name="username">
密码:<input type="text" name="userpassword">
<input type="submit" value="登陆" name="btn">
</form>
action中的属性名称要和jsp中的name一致
表达式封装(应用于属性为对象或List集合)
属性为对象
Bean中
public class User{
private String username;
private String userpassword;
....get/set方法。。。。
}
Aaction中
private User user;
....get/set方法....
jsp中
<form action="test">
用户名:<input type="text" name="user.username">
密码:<input type="text" name="user.userpassword">
<input type="submit" value="登陆" name="btn">
</form>
属性为List
Aaction中
private List<User> list;
....get/set方法....
jsp中
<form action="test">
用户名:<input type="text" name="list[0].username">
密码:<input type="text" name=" list[0].userpassword">
<input type="submit" value="登陆" name="btn">
</form>
模型驱动封装
将action实现ModelDriven接口
action中
public class CheckAction extends ActionSupport implements ModelDriven<User>{
private User user=new User();
public User getModel() {
return user;
}
//.....省略
}
getModel为接口中的方法,注意:一定得将属性user实例化。
jsp页面表单中的input中的name属性值与user中的属性值相同。
Struts2获取域对象Request,Response,Session
使用ActionContext对象获取
//获取request对象方法
ActionContext context=ActionContext.getContext();
HttpServletRequest request=(HttpServletRequest) context.get(org.apache.struts2.StrutsStatics.HTTP_REQUEST);
//获取request对象方法
HttpServletResponse response=(HttpServletResponse) context.get(org.apache.struts2.StrutsStatics.HTTP_RESPONSE);
//获取session对象
Map<String, Object> session=context.getSession();
ServletActionContext对象获取
//获取request对象方法
HttpServletRequest request2=ServletActionContext.getRequest();
其他域对象获取方式相似
ServletRequestAware接口获取
public class testaware extends ActionSupport implements ServletRequestAware,SessionAware{
HttpServletRequest request;
Map<String, Object> session;
public void setSession(Map<String, Object> arg0) {
this.session=arg0;
}
public void setServletRequest(HttpServletRequest arg0) {
this.request=arg0;
}
//response省略
}
ActionContext,Valuestack,StackContext联系
ActionContext:一次Action调用都会创建一个ActionContext,ActionContext是Action上下文
ValueStack(值栈):Struts2将OGNL上下文设置为Struts2中的ActionContext(内部使用的仍然是OgnlCont设为OGNL的根对象。
StackContext(map):stack上下文,它包含一系列对象,包括request、session、attr、applicationmap等。
ValueStack是一个list,ContextMap是一个Map型的数据结构,它是以键值对的形式的存储数据的。
我们在JSP页面中访问value stack的内容时,是不用加#,而如果是访问stack context的其他对象则要加上#。
<s:property value="name"/> Action中有name属性,或者有User属性其中User里有name属性,存值在ValueStack里,不用加#
<s:property value="#request.testValue"/> 取request域里的testValue值,request域在StackContext里,需加#
获取值栈
ActionContext context=ActionContext.getContext();
ValueStack stack=context.getValueStack();
stack.set("setValue", "set方法值");
stack.push("push方法值"); //push方法存的为数值形式
获取值栈set与push方法的值
<s:property value="setValue"/>
<s:property value="[0].top"/> //top是值栈里的数组
ValueStack(值栈)中获取list集合
遍历集合list
Struts2校验器
手工编码校验器
例子:
public class CheckAction extends ActionSupport implements ModelDriven<User>{
private User user=new User();
public User getModel() {
return user;
}
//Regist对应的校验方法
public void validateRegist() {
if(user.getPasswordAge()==null||user.getPasswordAge().equals("")){
this.addActionError("确认密码不能为空");
}else if(!user.getPassword().equals(user.getPasswordAge())){
this.addActionError("两次密码不一样");
}
}
public String Regist() {
System.out.println("注册成功");
ActionContext context=ActionContext.getContext();
ValueStack stack=context.getValueStack();
stack.set("mess", user.getName()+"注册成功!!");
return SUCCESS;
}
//Login对应的校验方法
public void validateLogin() {
//验证数据库信息,
//省略
System.out.println("验证数据库信息");
}
public String Login() {
System.out.println("登陆成功");
ActionContext context=ActionContext.getContext();
ValueStack stack=context.getValueStack();
stack.set("setValue", "set方法值");
stack.push("push方法值");
HttpServletRequest request=ServletActionContext.getRequest();
request.setAttribute("testValue", "获取成功");
return SUCCESS;
}
//统一校验方法
public void validate() {
if(user.getName()==null||user.getName().equals("")){
this.addActionError("用户名不能为空");
}else if(user.getPassword()==null||user.getPassword().equals("")){
this.addActionError("密码不能为空");
}else if(user.getName().length()>7){
this.addActionError("用户名过长,只能7个字符");
}
}
}
1.执行此Action时都会先执行validate()方法。然后执行execute()方法。
2.当核心文件配置访问此action的Login()方法时,会先执行ValidateLogin()方法,然后执行validate方法,最后才执行 Login方法。
3.当校验器执行 this.addActionError("message“); 执行停止,默认返回input。
基于xml配置文件的校验器
xml配置文件的校验器的名称是固定的,当action类名称为xxx时,配置文件名称为xxx-validation.xml,和action在同一目录。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="name">
<field-validator type="requiredstring">
<message>用户名不能为空</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<message>密码不能为空</message>
</field-validator>
</field>
<field name="dates">
<field-validator type="date">
<param name="min">1990-01-01</param>
<param name="max">1999-01-01</param>
<message>
日期格式不正确 最小为${min},最大为${max}
</message>
</field-validator>
</field>
</validators>
<message>标签为错误时的提示信息,<field>标签中的name的值要跟action中的类属性值一致。
校验器常用值
Struts2拦截器
拦截器:动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在 一个action执行前阻止其执行。过滤器和拦截器的区别
1.过滤器:过滤器理论上可以过滤任意内容,比如html,jsp,servlet,图片路径等;
2.拦截器:只能拦截action;
3.拦截器是基于java反射机制的,而过滤器是基于函数回调;拦截器不依赖与servlet容器,过滤器依赖与servlet容器
拦截器的实现
Interceptor接口
Interceptor接口定义三个方法,在intercept方法中写逻辑public class TestInterceptor implements Interceptor{
public void destroy() {
// TODO Auto-generated method stub
}
public void init() {
// TODO Auto-generated method stub
}
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("Interceptor执行。。。。");
invocation.invoke();//通过方法
return null;
}
}
AbstractInterceptor抽象类
AbstractInterceptor实现了Interceptor接口,继承时只需要重写intercept方法即可
public class TestInterceptor extends AbstractInterceptor{
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("Interceptor执行。。。。");
invocation.invoke();
return null;
}
}
MethodFilterInterceptor类
public class TestInterceptor extends MethodFilterInterceptor{
protected String doIntercept(ActionInvocation invocation) throws Exception {
String name=invocation.getInvocationContext().getName();//返回调用的action名称
System.out.println(name);
invocation.invoke();//执行invoke()方法后执行action,执行action后继续往下执行
return null;
}
}
MethodFilterInterceptor方法实现了AbstractInterceptor抽象类,会自动执行doIntercept()方法,只需要重写它即可。
struts_default.xml中配置
<!-- 配置拦截器 -->
<package name="interceptor" extends="struts-default">
<interceptors>
<interceptor name="testInterceptor" class="ynk.itcast.intorceptor.TestInterceptor"></interceptor>
</interceptors>
</package>
<!-- action包继承拦截器的包 -->
<package name="demo" extends="interceptor" namespace="/">
<action name="loginAction" class="ynk.itcast.action.CheckAction" method="Login">
<result name="success">/welcome.jsp</result>
<result name="input">/index.jsp</result>
<!-- 引用拦截器 -->
<interceptor-ref name="checkInterceptor"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
<!-- 默认拦截器,当定义拦截器时得手动添加默认拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
也可:
package name="interceptor" extends="struts-default">
<interceptors>
<interceptor name="checkInterceptor" class="ynk.itcast.intorceptor.CheckInceterceptor"></interceptor>
<interceptor name="testInterceptor" class="ynk.itcast.intorceptor.TestInterceptor"></interceptor>
<interceptor-stack name="totalInterceptor">
<interceptor-ref name="checkInterceptor"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
<!-- 默认拦截器,当定义拦截器时得手动添加默认拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
</package>
<!-- action包继承拦截器的包 -->
<package name="demo" extends="interceptor" namespace="/">
<action name="loginAction" class="ynk.itcast.action.CheckAction" method="Login">
<result name="success">/welcome.jsp</result>
<result name="input">/index.jsp</result>
<!-- 引用拦截器 -->
<interceptor-ref name="totalInterceptor"></interceptor-ref>
</action>
</package>
Interceptor,AbstractInterceptor实现的拦截器默认拦截所有方法,而MethodFilterInterceptor可配置xml文件选择拦截的方法
具体实现是在action中的 interceptor-ref 标签中定义参数。
<interceptor-ref name="testInterceptor">
<param name="includeMethods">login,register</param>
</interceptor-ref>
表示只拦截login和register方法。当name值为
excludeMethods 时表示除了login和register方法,其他都拦截。
文件S
Struts2上传文件
jsp页面中:
enctype默认值为 application/x-www-form-urlencoded 基于文件传输的要改为multipaart/form-data 且为post 方式。
<form action="uploadAction1" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="提交">
</form>
Bean:
利用Struts2文件上传时,默认执行fileUpload拦截器,将文件信息自动赋值
public class UploadFile{
private File file;
private String fileFileName; //命名格式固定:xxxFileName
private String fileContentType; //命名格式:xxxContentType
//....省略get.set方法
}
action:
public class uploadAction1 extends ActionSupport implements ModelDriven<UploadFile>{
UploadFile file=new UploadFile();
public UploadFile getModel() {
// TODO Auto-generated method stub
return this.file;
}
@Override
public String execute() throws Exception {
//项目目录加上/a 赋值给path
String path=ServletActionContext.getServletContext().getRealPath("\\a");
File pathFile=new File(path);
if(!pathFile.exists()){
pathFile.mkdir();
}
//根据pathFile和文件fileFileName新建目标文件
File goalFile=new File(pathFile,file.getFileFileName());
if(!goalFile.exists()){
goalFile.createNewFile();
}
//将源文件copy到目标文件
FileUtils.copyFile(file.getFile(), goalFile);
//也可用下面语句,将源文件修改名称后放到pathfile目录
/*file.getFile().renameTo(new File(pathFile, file.getFileFileName()));*/
return SUCCESS;
}
}
此例子中类属性为Bean类型,使用了模型驱为UploadFile类型的file属性封装数据。其中,UploadFile中的fileName为上传的文件名,fileContentType为文件类型。
当不用模型驱动时可设置action的三个类属性也可封装数据
private File file;
private String fileName;
private String fileContentType;
xml配置文件
<param>标签未 fileUpload拦截器的allowedeTypes属性赋值,即允许上传的文件格式,非此类格式时返回input。
<package name="action" extends="struts-default">
<action name="*" class="ynk.itcast.action.{1}">
<result name="success">/welcome.jsp</result>
<result name="input">/index.jsp</result>
<interceptor-ref name="defaultStack">
<param name="fileUpload.allowedTypes">
image/bmp,image/png,image/gif,image/jpeg,image/jpg
</param>
</interceptor-ref>
</action>
</package>
另:
maximumSize:表示上传文件大小的上限,单位是byte。默认2MB。
allowedTypes:表示允许上传文件的类型,每个类型之间用逗号分隔开(ie: text/html, image/jpg)。
allowedExtensions:表示允许上传以这些后缀结尾的文件,每个后缀之间用逗号分隔开(ie: .html, .jpg)。
多文件上传
实现多文件上传时只需要将action的类属性设为数组 如File[] file;String[] fileName 即可,然后将其遍历,jsp表单中type为file的input标签的name一致。
Struts2文件下载
先进入index Action 为 fileFileNames 赋值;
indexAction:
public class indexAction extends ActionSupport{
private String[] fileFileNames;
public String[] getFileFileNames() {
return fileFileNames;
}
public void setFileFileNames(String[] fileFileNames) {
this.fileFileNames = fileFileNames;
}
@Override
public String execute() throws Exception {
String path=ServletActionContext.getServletContext().getRealPath("\\download");
File pathFile=new File(path);
fileFileNames=pathFile.list(); //将pathFile路径下的所有文件名返回给数组fileFileNames
return SUCCESS;
}
}
index.jsp:
遍历fileFileNames
<s:iterator value="fileFileNames" var="fileFileName">
<a href="downloadAction?fileFileName=<s:property value='fileFileName'/>"><s:property value="fileFileName"/></a>
</s:iterator>
DownloadAction:
public class DownloadAction extends ActionSupport{
//需要下载的文件名
private String fileFileName;
public String getFileFileName() throws Exception {
return URLEncoder.encode(fileFileName, "UTF-8"); //转码,如果不转中文在下载时会没有文件名
}
public void setFileFileName(String fileFileName){
this.fileFileName = fileFileName;
}
public String execute() throws Exception {
return SUCCESS;
}
public InputStream getDownloadFile() {
return ServletActionContext.getServletContext().getResourceAsStream("\\download\\"+fileFileName);//获取文件流
}
}
xml配置文件:
type类型为stream;
inputName标签里的download表示获取文件流的方法;
contentDisposition中的attchment表示下载文件而不是打开;filename的值为下载时的文件名。
<package name="action" extends="struts-default">
<action name="downloadAction" class="ynk.itcast.action.DownloadAction">
<result name="success" type="stream">
<param name="inputName">downloadFile</param><!-- 调用的方法 -->
<!-- attchment表示为下载而不是打开,filename后接下载的文件名 -->
<param name="contentDisposition">attchment;filename=${fileFileName}</param>
</result>
</action>
<action name="index" class="ynk.itcast.action.indexAction">
<result name="success">/index.jsp</result>
</action>
</package>
Struts2异常信息
addActionError
添加错误信息:
this.addActionError("错误信息1");
显示信息标签为:
<s:actionerror/>
addActionMessage
添加错误信息:
this.addActionMessage("错误信息1");
显示信息标签为:
<s:actionmessage/>
addFieldError
添加错误信息:
this.addFieldError("error", "错误信息");
this.addFieldError("error1", "错误信息1");
显示全部信息标签为:
<s:fielderror/>
或:
<s:fielderror>
<s:param>error</s:param>
<s:param>error1</s:param>
</s:fielderror>