配置文件
一、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>
<!--package中
name:package的名称,用来多个package的区分
namespace:命名空间 默认为/ ,如果namespace="/e",则访问路径为localhost/HelloAction/e/hello
extends:属性固定值,默认struts-default
-->
<package name="demo" extends="struts-default" namespace="/">
<!--action中
method默认执行execute方法
class =包+.类名
通过name访问
-->
<action name="hello" class="com.lx.demo.helloAction" method="">
<!--
result中
name与method指定方法的返回值一致
默认的name值是“success
type:配置如何到另外一个路径中去(转发或者重定向)默认为转发
-->
<result name="ok">/index.jsp</result>
</action>
</package>
<package name="demo2" extends="struts-default" namespace="/e">
<action name="login" class="com.lx.demo.helloAction" method="login">
<result name="log">/test.jsp</result>
</action>
</package>
<!--覆盖系统默认常量(libraties下struts2-core-2.5.20.jar包里面的
org.apache.struts2里的default,properties) -->
<constant name="struts.i18n.encoding " value="GBk"></constant>
</struts>
-
<package>
标签,如果要配置<Action>的标签,那么必须要先配置<package>标签,代表的包的概念
- 包含的属性
-
name
-- 包的名称,要求是唯一的,管理action配置 -
extends
-- 继承,可以继承其他的包,只要继承了,那么该包就包含了其他包的功能,一般都是继承struts-default -
namespace
-- 名称空间,一般与<action>标签中的name属性共同决定访问路径(通俗话:怎么来访问action),常见的配置如下- namespace="/" -- 根名称空间
- namespace="/aaa" -- 带有名称的名称空间
-
abstract
-- 抽象的。这个属性基本很少使用,值如果是true,那么编写的包是被继承的
-
-
<action>
标签
- 代表配置action类,包含的属性
-
name
-- 和<package>标签的namespace属性一起来决定访问路径的 -
class
-- 配置Action类的全路径(默认值是ActionSupport类) -
method
-- Action类中执行的方法,如果不指定,默认值是execute
-
-
<result>
标签
- action类中方法执行,返回的结果跳转的页面
-
name
-- 结果页面逻辑视图名称 -
type
-- 结果类型(默认值是转发,也可以设置其他的值)
-
二、模块化struts.xml文件的方法
- 文件拆分为多个xml文件,并用以下方式导入它们
<struts>
<include file="com/lx/frist/test/struts-pay.xml"></include>
<include file="com/lx/second/test/struts-user.xml"></include>
</struts>
三、通配符实现
访问时用http://localhost/HelloAction/p/user_add
<package name="Pay" extends="struts-default" namespace="/p">
<action name="user_*" class="com.lx.frist.test.PayAction" method="{1}" >
<result name="add">/index.jsp</result>
<result name="delete">/index.jsp</result>
<allowed-methods>add,delete</allowed-methods>
</action>
</package>
四、注意
配置xml文件时需要极其非常一定要注意的点:
<package>
标签的namespace在访问时需要用到,很重要
-
<action>
标签的method方法默认执行execute方法 </br>如果表单要提交的方法不是execute,而是其他方法,如:在<form>
标签里配置的action是login.action,
<form action="<%=request.getContextPath() %>/login.action ">
而xml里name为login的这个action没有给method赋值,此时将会出现404There is no Action mapped for namespace [/u] and action name [login] associated with context path [/HelloAction].
也就是说如果需要该action执行的方法不是execute方法,那么一定要将真正需要执行的方法名赋值给method - 用通配符访问需要注意向Action类里面添加方法或者修改方法名后,一定要
<allowed-methods>
标签里添加该方法,不然又会出现404
Action
自定义Action一般继承ActionSupport类
- Action访问Servlet-API
-
让Action类实现对应aweargan感知接口ServletRequestAwear,ServletresponseAwear,SessionAwear分别获取
public class TestAction implements ServletRequestAware,ServletResponseAware { private HttpServletRequest request; private HttpServletResponse response; @Override public void setServletResponse(HttpServletResponse response) { this.response=response; } @Override public void setServletRequest(HttpServletRequest request) { this.request=request; }
}
-
通过ServletActionContext工具类
public class TestAction { public String getObject() { HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); HttpSession session = ServletActionContext.getRequest().getSession(); return null; } }
-
通过ActionContext类
获取Action的上下文对象ActionContext.getContext(),在ActionContext中把request,session,application三大作用域对象作为Map对象,通过Map对象即可获取import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.opensymphony.xwork2.ActionContext; public class TestAction { public String getObject() { // ActionContext context = ActionContext.getContext(); // Map request = (Map)context.get("request"); // Map session = context.getSession(); HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(org.apache.struts2.StrutsStatics.HTTP_REQUEST); HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(org.apache.struts2.StrutsStatics.HTTP_RESPONSE); Map<String, Object> session = ActionContext.getContext().getSession(); session.put("USER-INFO", userName);//在session中保存 return NONE; } }
拦截器
拦截器实现以下操作:
- 在调用action之前提供预处理逻辑。
- 在调用action后提供后处理逻辑。
- 捕获异常,以便可以执行备用处理。
一、自定义拦截器
- 实现
com.opensyphony.xwork.interceptor.interceptor
- 继承
com.opensyphony.xwork.interceptor.AbstractInterceptor
- 根据具体需要重写intercepter方法
- 在struts.xml中注册拦截器
- 如果某个Action有制定拦截器,默认拦截器将无效
方式一:
<interceptors>
<interceptor name="DemoInterceptor" class="com.itheima.interceptor.DemoInterceptor"/>
</interceptors>
<action name="userAction" class="com.itheima.demo3.UserAction">
<!-- 只要是引用自己的拦截器,默认栈的拦截器就不执行了,必须要手动引入默认栈 -->
<interceptor-ref name="DemoInterceptor"/>
<interceptor-ref name="defaultStack"/>
</action>
方式二:
<interceptors>
<interceptor name="DemoInterceptor" class="com.itheima.interceptor.DemoInterceptor"/>
<!-- 定义拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="DemoInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<action name="userAction" class="com.itheima.demo3.UserAction">
<!-- 引入拦截器栈 -->
<interceptor-ref name="myStack"/>
</action>
思考1:如果package有100个action,其中98个需要用到某个拦截器,怎么办?
可以将该拦截器和默认拦截器栈添加到自己定义的拦截器栈(方法二),并且定义为默认拦截器栈<default-interceptor-ref name = "myStack">
思考2:按照上述解决方法,那剩余两个不用该拦截器却使用了该拦截器,这个时候怎么办?
给这两个单独加自己的拦截器,这样会覆盖之前定义的默认拦截器栈myStack,一般误其他要求引入defaultStack
就好,也就是加上这行代码
<interceptor-ref name = "defaultStack" />
二、方法拦截器
- 拦截器继承
MethodFilterInterceptor
类 - 细化到拦截某个方法,而不是某个Action
- 指定需拦截或无需拦截的方法,在<interceptor-ref>标签里加入代码
-
<param name = "excludeMethods">方法名</param>
多个方法用逗号隔开,指明拦截器不要拦截的方法 -
<param name = "includeMethods">方法名</param>
指明所要拦截的方法
注意:includeMethod优先于excludeMethod
ONGL、值栈、标签库
前提:<%@ taglib prefix="s" uri="/struts-tags" %>
ONGL\标签库
https://blog.csdn.net/shaonianbz/article/details/79145925
值栈
https://blog.csdn.net/shaonianbz/article/details/79183725
文件上传,下载
一、文件上传
- 文件上传配置
-
文件上传条件:
(1)用post方式
(2)使用二进制编码:multipart/form-data
(3)<input type="file" name="***" />
<form action="upload" method="post" enctype="multipart/form-data"> <label for="myFile">Upload your file</label> <input type="file" name="myFile" /> <input type="submit" value="Upload"/> </form>
上传文件默认为2M,可以通过修改常量设置,如:
<constant name="struts.multipart.maxSize" value="1000000" />
-
如果只想对当前form表单有效,可以设置fileUpload拦截器属性
<action name="upload" class="cn.w3cschool.struts2.uploadFile"> <interceptor-ref name="basicStack"> <interceptor-ref name="fileUpload"> <param name="maximumSize">20971520</param><!-- 文件最大20m --> <param name="allowedTypes">image/jpeg,image/gif</param> <!--设置上传文件允许的后缀名,多个使用逗号隔开 --> <param name="allowedExtensions"></param> </interceptor-ref> <result name="success">/success.jsp</result> <result name="error">/error.jsp</result> </action>
还可以设置上传文件允许的后缀名,多个使用逗号隔开如: <param name="allowedExtensions">txt,avi</param>
- 关于限制文件大小,如果限制的最大值超过2M则需要在struts.xml中增加
<constant name="struts.multipart.maxSize" value="21000000"/>
,这行代码表示整个项目所有要上传文件的地方允许上传的文件大小的最大值,也就是说这个项目里上传的任何单个文件大小不能超过21000000字节(约20M),如果项目中不添加这行代码,则默认允许上传的文件大小最大为2M, - 超过文件总大小时,跳转Input,
2 . action类代码需要注意的是:
(1)上传文件名命名规则:上传的字段名(form表单中的input的name)+FileName
(2)MIME类型命名规则:上传的字段名(form表单中的input的name)+ContentType
(3)表单中提供的属性和struts提供的属性需要set,get方法
(4)注意需要导入包,如下
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class PayAction extends ActionSupport {
private File myFile;
private String myFileFileName;
private String myFileNameContentType;
@Override
public String execute() {
System.out.println("进入pay");
return SUCCESS;
}
public String addd() {
System.out.println("add");
return "add";
}
public String delete() {
System.out.println("delete");
return "delete";
}
public String upload(){
//获取项目部署到的磁盘绝对路径
String realPath = ServletActionContext.getServletContext().getRealPath("/");
System.out.println(realPath+"dahfo");
//指定目录创建文件
File destFile = new File(realPath, myFileFileName);
//复制到指定目录的文件
try {
FileUtils.copyFile(myFile,destFile);
myFile.delete();
} catch (IOException e) {
e.printStackTrace();
return "fail";
}
return "ok";
}
public File getMyFile() {
return myFile;
}
public void setMyFile(File myFile) {
this.myFile = myFile;
}
public String getMyFileFileName() {
return myFileFileName;
}
public void setMyFileFileName(String myFileFileName) {
this.myFileFileName = myFileFileName;
}
public String getMyFileNameContentType() {
return myFileNameContentType;
}
public void setMyFileNameContentType(String myFileNameContentType) {
this.myFileNameContentType = myFileNameContentType;
}
}
二、文件下载
- xml配置
<package name="p2" extends="struts-default">
<action name="download" class="com.san.action.Download" method="download">
<!--stream类型:直接向页面输出二进制数据 -->
<result name="ok" type="stream">
<!-- 给stream结果视图注入参数:Content-Type -->
<param name="contentType">application/octet-stream</param>
<!-- 告知浏览器一什么方式打开 ${@java.net.URLEncoder@encode(fileName,"UTF-8")}-->
<param name="contentDisposition">attachment;fileName=1.jpg</param>
<!-- 注入字节流,取值要写动作类中的set方法名称,首字母改成小写 -->
<param name="inputName">inputStream</param> </result>
</action>
</package>
- action核心代码
public String download() throws Exception{
//1、找到文件存储位置
String filePath=ServletActionContext.getServletContext().getRealPath("/WEB-INF/download/file1.txt");
file = new File(filepath,fileName);
//2、把文件读入到InputStream流中
inputStream=new FileInputStream(file);
return "ok";
}
public InputStream getInputStream() {
return inputStream;
}
-
jsp文件,开头引入标签库
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:a namespace="/p" action="download">文件下载1 <s:param name="fileName" value="%{'file1.txt'}"></s:param> </s:a> <a href="<%= request.getContextPath()%>/p/download.action?fileName=file1.txt">2</a>