Struts2框架
Struts2 用来替换 Servlet — 升级版(对于原始Servlet技术的封装)
框架:半成品,解决现有软件开发中所存在的通用问题,为了提升开发效率。
Servlet中存在哪些问题?
- 接收数据冗余
- String s = request.getParameter(""); 冗余
- 需要将接收的数据进行数据类型的转换。
- post请求的数据提交,需要编码过滤器。
- 跳转路径硬编码在源文件中(写死了)
一、第一个Struts2程序
1、编码思想
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2qR4CyQp-1594711299913)(E:\JavaWeb\Struts\笔记\思想.png)]
localhost:8989/项目名称/url-pattern servlet
localhost:8989/项目名称/struts.xml 中action标签的name属性值
2、代码开发
1. 搭建开发环境
1、 jar包
九个jar包
2、 准备struts.xml的配置文件
位置: 必须是src的根目录
3、 在web.xml中配置struts2的核心过滤器 (没有配置 404)
apache: www.apache.org
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.
StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. java编码
实现 Action接口
import com.opensymphony.xwork2.Action;
public class MyAction implements Action {
@Override
public String execute() throws Exception {
System.out.println("--------Hello Wolrd----------");
return "success";
}
}
3.struts.xml的配置
<!-- 包 struts.xml中的package 和 java src中package没有任何关系 -->
<package name="day1" extends="struts-default">
<!-- localhost:8989/Struts_Day1/first -->
<action name="first" class="com.baizhi.action.MyAction">
<!-- name="类中execute方法的返回值" -->
<result name="success">/index.jsp</result>
</action>
</package>
支持 路径 + .action 结尾的后缀名
http://localhost:8989/Struts_Day1/first.action
二、跳转
两种跳转: forward 请求转发 、redirect重定向
<result name="success" type="使用的跳转方式">目标路径</result>
Action —> jsp 跳转
1. 默认是forward 请求转发跳转方式
<!-- type="dispatcher" -->
<result name="success" type="dispatcher">页面</result>
2. redirect 重定向
<!-- type="redirect" -->
<result name="success" type="redirect">页面</result>
Action —> Action跳转
1. forward 请求转发
<!-- type="chain" -->
<action name="first" class="com.baizhi.action.MyAction">
<!-- second:另一个action的name属性-->
<result name="success" type="chain">second</result>
</action>
<action name="second" class="com.baizhi.action.MyAction2">
<result name="success">/index.jsp</result>
</action>
2. redirect 重定向
<!-- type="redirectAction" -->
<action name="first" class="com.baizhi.action.MyAction">
<!-- second:另一个action的name属性-->
<result name="success" type="redirectAction">second</result>
</action>
<action name="second" class="com.baizhi.action.MyAction2">
<result name="success">/index.jsp</result>
</action>
跳转四个小分类(本质上都是forward和redirect)
action --> jsp dispatchar(默认) / redirect
action --> action chain /
注意: 如何获取request等对象?
使用工具类 ServletActionContext
HttpServletRequest request = ServletActionContext.getRequest();
三、package标签
对于整个项目中的Action进行分类管理
1、namespace 命名空间
<!-- 包 struts.xml中的package 和 java src中package没有任何关系 -->
<!-- name="day1" 随便写 只要配置文件中没有明明冲突即可 -->
访问路径: localhost:8989/项目名称/namespace/action标签name的属性值
localhost:8989/Struts_Day1/d/first.action
<package name="day1" extends="struts-default" namespace="/d">
<!-- localhost:8989/Struts_Day1/first.action -->
<action name="first" class="com.baizhi.action.MyAction">
<result name="success" type="redirectAction">second</result>
</action>
<action name="second" class="com.baizhi.action.MyAction2">
<result name="success">/index.jsp</result>
</action>
</package>
2、Streuts 挎包跳转的问题
只针对Action ----> Action的跳转
<package name="day1" extends="struts-default" namespace="/d1">
<action name="first" class="com.baizhi.action.MyAction">
<result name="success" type="redirectAction">
<!-- 声明跳转到的 package的 namespace名称 和 具体的action标签的name -->
<param name="namespace">/d2</param>
<param name="actionName">second</param>
</result>
</action>
</package>
<package name="day2" extends="struts-default" namespace="/d2">
<action name="second" class="com.baizhi.action.MyAction2">
<result name="success">/index.jsp</result>
</action>
</package>
注意:在挎包跳转中 <result name="xxxx" type="有几个可选值?">
只能写: chain / redirectAction
四、Struts2中接收数据 — 使用成员变量
使用成员变量接收数据!!!!
Struts2的Action对象是否也是单例呢?
每一次访问Action对象 都会调用Action中的无参构造方法,Action不是单例对象。
login.jsp
<form action="xxxxxxx" method="post">
<input type="text" name="username"/>
<input type="text" name="age"/>
<input type="text" name="date"/>
</form>
Servlet 中
保证存在编码过滤器
String username = request.getParameter("username");
String age = request.getParameter("age");
int a = Integer.parseInt(age);
String date = request.getParameter("date");
Date d = new simpleDateFormate("yyyy-MM-dd").parse(date);
1. 接收简单类型的数据 八种基本类型+String+Date
class MyAction implements Action{
private String username;
private int age;
// yyyy-MM-dd HH:mm:ss
private Date date;
set/get方法
// 接收中文数据的默认格式是utf-8
public String execute()throws Exception{
username / age / date
return "success";
}
}
2. 使用自定义对象类型接收数据
User对象 id name password
class MyAction implements Action{
private User u;
set/get方法
public String execute()throws Exception{
System.out.print(user);
return "success";
}
}
页面 .jsp name = 成员变量名称.属性
<input type="text" name="u.id"/>
<input type="text" name="u.name"/>
<input type="text" name="u.password"/>
3. 批量删除 接收集合类型的数据
<input type="checkbox" name="ids"/>
<input type="checkbox" name="ids"/>
<input type="checkbox" name="ids"/>
Servlet中
String[] strs = request.getParametervalues();
Struts中 使用集合类型接收
private List<Integer> ids ;
set/get;
五、DMI开发方式
Action 开发 必须去实现Action接口!!!
Action数量的不可控, 使用DMI开发方式去减少Action的数量。
继承 ActionSupport类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C2wJmiQw-1594711299915)(E:\JavaWeb\Struts\笔记\DMI.png)]
配置Struts.xml 两种情况
1、配置方式一:
<package name="day2" extends="struts-default">
<action name="login" class="com.baizhi.action.MyAction" method="loginMethod">
<result name="loginSuccess">/index.jsp</result>
</action>
<action name="register" class="com.baizhi.action.MyAction"
method="registerMethod">
<result name="registerSuccess">/index.jsp</result>
</action>
</package>
localhost:8989/项目名称/action标签中的name属性值
2、配置方式二:
<package name="day2" extends="struts-default">
name=“my_*”
<action name="*" class="com.baizhi.action.MyAction" method="{1}">
<result name="loginSuccess">my_</result>
<result name="registerSuccess">/index.jsp</result>
</action>
</package>
method=“{1}” 使用 方法名 去替换 name属性值中的 *
localhost:8989/项目名称/action标签中的name属性值 * -----> 方法名称
localhost:8989/项目名称/loginMethod
localhost:8989/项目名称/my_loginMethod
注意: 同一个Action中 方法之间的返回值必须不一样!!!!
六、使用成员变量替换request作用域
替换了request作用域存入数据的代码,而不是取代了作用域,底层还是使用request作用域完成的数据传递。
public class MyAction2 implements Action{
//使用成员变量替换request作用域
private String key ="value";
@Override
public String execute() throws Exception {
System.out.println("-----------第二个Action-----------");
//HttpServletRequest request = ServletActionContext.getRequest();
//request.setAttribute("key", "value");
return "success";
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
<h3>${requestScope.key}</h3>
request.setAttribute(String name, object value);
key = 成员变量的名称 = String name
七、文件的上传
1、 页面如何选择文件进行发送
2、 Action如何就收发送的数据文件
3、 服务器如何去保存文件
1、页面
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name=""/>
<input type="submit"/>
</form>
1. type = "file"
2. enctype="multipart/form-data"
2、Action接收数据
import java.io.File;
//Action中接收前台提交的数据
private File upload;
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
3、 服务器保存文件
使用IO流将内存中的文件数据写入服务器硬盘中
// 创建流 创建去读单位大小 使用循环依次写入硬盘中 -1 关闭资源
InputStream is = new FileInputStream(upload);
OutputStream os = new
FileOutputStream("F:\\apache-tomcat-7.0.64\\webapps\\Struts_Day3\\b.txt");
byte[] b = new byte[2048];
int len = 0;
while(true){
len = is.read(b, 0, b.length);
if(len==-1){
break;
}else{
os.write(b);
}
}
is.close();
os.close();
return "success";
问题
1、文件名称以及文件类型无法动态获取
Action 中 定义成员变量
private String 上传的文件名称+FileName; //获取文件的上传名称
private String 上传的文件名称+ContentType; //获取文件的互联网类型
set/get 方法
2、不使用原始的IO流进行文件的上传 效率有一定问题
FileUtils.copyFile(upload,
new File("F:\\apache-tomcat7.0.64\\webapps\\Struts_Day3\\file\\"+uploadFileName));
FileUtils.copyFile(上传的文件对象,new File(服务器保存文件的路径));
**上传的文件大小设置 ** 默认2m
Struts.xml
<constant name="struts.multipart.maxSize" value="20971520000"></constant>
3、上传路径动态获取
//获取项目所在服务器的真实路径
//name 具体的文件夹名称
private String name;
set/get方法
String realPath = ServletActionContext.getServletContext().getRealPath(name);
Strust.xml中
<action name="upload" class="com.baizhi.action.MyAction" method="upload">
<!-- 上传文件的目标文件夹名称 -->
<param name="name">f</param>
<result name="success">/index.jsp</result>
</action>
成员变量
1、接收数据 2、替换request作用域传递数据 3、从struts.xml文件中获取数据信息
文件上传代码
//Action中接收前台提交的数据
private File upload;
//获取上传文件的文件名称 文件名对象upload + FileName; 自动获取文件名称
private String uploadFileName;
//文件名对象upload + ContentType; 获取文件的互联网类型
private String uploadContentType;
//定义成员变量 从strtus.xml文件中读取数据 动态从配置文件中读取到的文件名称
private String name;
public String upload()throws Exception {
//动态获取文件的保存路径 //将文件夹名称提取出来写在struts.xml的配置文件中
String realPath = ServletActionContext.getServletContext().getRealPath(name);
//copyFile 文件的复制 将源文件 复制到 制定的目标路径中
FileUtils.copyFile(upload, new File(realPath+"\\"+uploadFileName));
return "success";
}
八、拦截器
Action中存在代码冗余的问题,强制登录。
1、开发步骤
拦截器的开发
实现 interceptor接口
public class MyInterceptor implements Interceptor{
//三个方法
public String intercept(ActionInvocation ai) throws Exception {
System.out.println("-----------intercept------------");
ai.invoke(); //相当于 chain.doFilter() 放行
return null;
}
}
拦截器的配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lnCBAPfc-1594711299917)(E:\JavaWeb\Struts\笔记\拦截器配置.png)]
注意: 拦截器只在本包中生效 package标签中有效
使用DMI的第二种配置方式会减少部分拦截器配置的冗余。
2、配置补充
如果程序中存在多个拦截器应该如何进行配置 ?
拦截器栈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zytt3vz3-1594711299918)(E:\JavaWeb\Struts\笔记\拦截器栈1.png)]
每一个Action标签都是用拦截器栈 冗余
默认拦截器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0BAsHnp6-1594711299919)(E:\JavaWeb\Struts\笔记\默认拦截器栈.png)]
如何拦截器中存在跳转判断应该如何书写 ?
例如:当强制登录中没有进行过登录操作,则需要跳转回登录页面。
拦截器中的返回值 retrun “xxxx”; 跳转配置需要写在Action标签中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eBDEcbHv-1594711299920)(E:\JavaWeb\Struts\笔记\拦截器中的跳转.png)]
全局跳转
拦截器进行拦截跳转 可能存在多个Action标签中使用配置相同的访问跳转路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1iux95w-1594711299922)(E:\JavaWeb\Struts\笔记\全局跳转.png)]
注意: 当使用自定义拦截器的时候有可能会和Struts2框架定义的系统拦截器产生冲突。
在使用配置用户自定义拦截器栈是优先声明系统默认拦截器。
<interceptor-stack name="myStack">
<!--优先声明系统默认拦截器-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="login"></interceptor-ref>
</interceptor-stack>
3、方法拦截器
public class MyMethodInterceptor extends MethodFilterInterceptor{ //抽象类
@Override
protected String doIntercept(ActionInvocation ai) throws Exception {
System.out.println("-------方法拦截器----------");
ai.invoke();
return null;
}
}
配置
<!-- 配置方法拦截器的时候并不是拦截action中的所有 而是对部分方法进行拦截 -->
<interceptors>
<interceptor name="my"
class="com.baizhi.interceptor.MyMethodInterceptor">
<!-- excludeMethods 非包含 -->
<param name="includeMethods">my*</param>
</interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="my"></interceptor-ref>
</interceptor-stack>
</interceptors>
注意: 在Struts2中进行拦截器开发步骤
1、 拦截器 实现 interceptor接口
方法拦截器 继承 MethodFilterinterceptor抽象类
2、 配置
2.1 声明拦截器 (如果是方法拦截器还需要声明包含或非包含方法)
2.2 定义拦截器栈 (添加系统默认拦截器 defaultStack)
2.3 使用拦截器栈
2.3.1 在action标签中配置
2.3.2 使用默认的拦截器栈
九、文件下载
提交文件名称,从服务器中将文件通过流进行输出。
//文件所在文件夹的名称
private String name;
//浏览器提交的需要下载的文件名称 同时向struts.xml中进行赋值操作
private String fileName;
public InputStream getInputStream()throws Exception{
//获取文件所在服务器的真实路径
String realPath = ServletActionContext.getServletContext().getRealPath(name);
//name 文件在服务器中的路径
return new FileInputStream(realPath+"\\"+fileName);
}
<package name="down" extends="struts-default">
<!-- action中没有method属性 -->
<action name="download" class="com.baizhi.action.DownLoadAction">
<param name="name">file</param>
<!-- type="stream" 输出不再是跳转而是流对象 -->
<result type="stream">
<!-- contentType 输出文件的互联网类型 -->
<param name="contentType">image/png</param>
<param name="bufferSize">4096</param>
<!-- contentDisposition 保存方式 -->
<!-- inline 浏览器预览 -->
<!-- attachment;filename=${fileName} 使用附件的形式进行保存 -->
<param name="contentDisposition">attachment;filename=${fileName}</param>
</result>
</action>
</package>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U6EDxxFn-1594711299923)(E:\JavaWeb\Struts\笔记\下载.png)]
1. 成员变量 如何接收数据? 怎么做的 拦截器!!!
2. 成员变量为什么可以替换request作用域?
type=“stream” 输出不再是跳转而是流对象 -->
image/png
4096
attachment;filename=${fileName}
[外链图片转存中...(img-U6EDxxFn-1594711299923)]
- 成员变量 如何接收数据? 怎么做的 拦截器!!!
- 成员变量为什么可以替换request作用域?