Struts框架
一、引言
框架 : 代码的半成品 —> 功能的封装(强大)、通用性。
Servlet规范 冗余!! ----> 使用Struts2框架 替换 Servlet技术
1、Servlet的问题
1、 接收用户提交数据
String value = request.getParameter(String name);
1.1 冗余
1.2 编码格式的设置
1.3 类型转换
2、 跳转路径的硬编码
2.1错误的提示没有
2.2都需要修改源文件
2、Struts2开发的思想
二、开发步骤
1、环境搭建
1.1 导入jar包
核心jar包和三方jar包 9个
1.2 引入配置文件
必须将文件放在src的根目录中!
1.3 初始化配置 、 配置struts2的核心过滤器
使Struts2框架生效
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.
StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2、编码
实现Action接口
import com.opensymphony.xwork2.Action;
public class MyAction implements Action{
@Override
public String execute() throws Exception {
System.out.println("-----Action-----Struts2------");
return "firstAction";
}
}
3、配置struts.xml
<struts>
<!-- package 和 src中的包没任何关系 name="随便写" extends="规定" -->
<package name="day1" extends="struts-default">
<!-- name="访问路径" class=""全限定名称-->
<action name="my" class="com.baizhi.action.MyAction">
<!-- name="方法中的返回值" -->
<result name="firstAction">/index.jsp</result>
</action>
</package>
</struts>
补充
1、获取request、response
//工具类 ServletActionContext
HttpServletRequest request = ServletActionContext.getRequest();
2、访问路径
namespace = "/" 默认 /
访问路径 localhost:8989/项目名/namespace/action name
http://localhost:8989/Struts_Day1/user/my
http://localhost:8989/Struts_Day1/user/my.action
3、Action是单例还是多例????
Servlet 单例
Action 多例 ---> 可以定义成员变量
三、Struts2的跳转
两大类 : forward : 请求转发 / redirect:重定向
Action ----> Jsp(页面) : dispatcher (默认值) / redirect
Action ----> Action : chain / redirectAction
1、Action跳转至Jsp页面
Struts中进行跳转默认是forward请求转发,地址栏没有发生改变。
1、 forward : 请求转发
<action name="my" class="com.baizhi.action.MyAction">
<!-- name="方法中的返回值" -->
<result name="firstAction" type="dispatcher">/index.jsp</result>
</action>
2、 redirect:重定向
<action name="my" class="com.baizhi.action.MyAction">
<!-- name="方法中的返回值" -->
<result name="firstAction" type="redirect">/index.jsp</result>
</action>
2、Action跳转至Action
3、package标签
分包:在struts.xml中 跟java的包 没有任何关系。
1.namespace 命名空间
决定了本包中所有action访问的路径标识
2.跨包跳转
针对的是Action到Action的跳转
3.全局跳转
同包中存在不同action包含了相同的result返回跳转路径,则可以进行冗余配置的提取。
作用范围:仅同包!!!
package中标签存在配置书写顺序。
result-types?,interceptors?,default-interceptor-ref?,default-action-ref?,
default-class-ref?,global-results?,global-exception-mappings?,action*
使用Struts2技术+JDBC技术+Jsp技术
登陆 + 展示所有 跨包配置!!!
一、Struts2 使用成员变量接收数据
替换 request.getParameter ()
完成数据的接收 / 编码格式的设置(utf-8) / 数据类型的转换
1.1 接收基本类型数据 八种+String+Date
页面
Username: <input type="text" name="username"/></br>
Age: <input type="text" name="age"/></br>
Salary: <input type="text" name="salary"/></br>
Date: <input type="date" name="date"/></br>
Action中
private String username;
private int age;
private double salary;
private Date date;
set/get 方法
注意:成员变量名称 与 页面中 input标签的name属性
get : localhost:8989/项目/资源路径?name=value name就是成员变量名称
1.2对象类型
User对象
页面
Username: <input type="text" name="u.username"/></br>
Age: <input type="text" name="u.age"/></br>
Salary: <input type="text" name="u.salary"/></br>
Date: <input type="date" name="u.date"/></br>
Action
private User u;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
集合类型
User 中属性
private List<String> hobby;
页面中
<input type="checkbox" name="user.hobby" value="1"/>吃饭
<input type="checkbox" name="user.hobby" value="2"/>睡觉
<input type="checkbox" name="user.hobby" value="3"/>烫头
User [username=刘洋, age=123, salary=123.123,
date=Fri Dec 06 00:00:00 CST 2019, hobby=[2, 3]]
二、DMI 动态方法调用
Action的开发过程中 一个Action类只有一个execute方法。
问题----> Action类的数量过多不方便管理
1. 继承ActionSupport类
public class MyAction2 extends ActionSupport{
//继承ActionSupport 开发人员可以自定义方法
//减少了项目中Action的数量
//规定!!! 无参!!!!!
//public String 方法名随意()异常随意{}
public String loginMethod1(){
System.out.println("-----登陆方法-------");
return "loginMethod";
}
public String showAllMethod2(){
System.out.println("-----展示所有方法-------");
return "showAllMethod";
}
}
2.struts.xml 配置
配置方式之一
<package name="day2.am" extends="struts-default" namespace="/">
<action name="method1" class="com.baizhi.action.MyAction2"
method="loginMethod1">
<result name="loginMethod" type="redirect">/login.jsp</result>
</action>
<action name="method2" class="com.baizhi.action.MyAction2"
method="showAllMethod2">
<result name="showAllMethod" type="redirect">/login.jsp</result>
</action>
</package>
注意: action标签中多了一个属性 method ="同一个类中不同的方法名称”
配置方式之二
<package name="day2.am" extends="struts-default" namespace="/">
<!-- method_ 仅仅是为了区分使用 不加也行 -->
<action name="method_*" class="com.baizhi.action.MyAction2" method="{1}">
<result name="loginMethod" type="redirect">/login.jsp</result>
<result name="showAllMethod" type="redirect">/login.jsp</result>
</action>
</package>
<!-- 相同Action中不同的方法间的跳转 -->
<result name="loginMethod" type="redirectAction">method_showAllMethod2</result>
<result name="showAllMethod" type="redirect">/login.jsp</result>
三、使用成员变量替换request作用域
成员变量 没有去替换request作用域本身,而是对作用域进行了封装。
成员变量 = request.setAttribute(String name, Object value);
多个Action中如果有相似应用的需求,成员变量不能重名。
原始方式:
List<User> users = userService.showAllUsers();
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("users", users);
成员变量方式
private List<User> users;
set/get方法
users = userService.showAllUsers();
取值:
和之前一模一样
${requestScope.key} key=成员变量的名称
四、文件上传
1、页面
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
2、Action接收数据
Action中定义成员变量
private File file; set/get方法;
3、写入服务器硬盘
InputStream is = new FileInputStream(file);
OutputStream os = new FileOutputStream("F:/tomcat7/my.txt");
byte[] b = new byte[1024];
int len = 0; // -1 结束
while(true){
len = is.read(b, 0, b.length);
if(len==-1){
break;
}else{
os.write(b,0,len);
}
}
os.close();
is.close();
<package name="upload" extends="struts-default" namespace="/">
<action name="uploadFile" class="com.baizhi.upload.MyUpload"
method="uplaodFile">
<result name="uploadSuccess">/MyJsp.jsp</result>
</action>
</package>
4、待解决问题
1.文件名称如何获取
//文件的名称 上传的文件+FileName
private String fileFileName;
//文件的互联网类型 上传的文件+ContentType (一般在下载的时候使用)
private String fileContentType;
set、get方法
2.上传之后保存的路径写死了
String realPath = ServletActionContext.getServletContext().getRealPath("/file");
获取了:
服务器中项目的具体路径 --- 绝对路径
/file 项目中的具体文件夹
3.原始IO效率低下
FileUtils.copyFile(file, new File(realPath+"/"+fileFileName));
4.文件上传的大小限制
默认2M 在struts.xml中可以配置
struts.multipart.maxSize = 2097152
<constant name="struts.multipart.maxSize" value="20971520000"></constant>
5.成员变量可以获取struts.xml中的配置信息
<action name="uploadFile" class="com.baizhi.upload.MyUpload" method="uplaodFile">
<param name="saveFile">/file</param>
<result name="uploadSuccess">/MyJsp.jsp</result>
</action>
java:
private String saveFile;
set/get
String realPath = ServletActionContext.getServletContext().getRealPath(saveFile);
一、配置文件分包
<struts>
<!--包含其他配置文件 但是struts.xml只能有一个 最终一定是引入带struts.xml里-->
<include file="struts_user.xml"></include>
<package name="user" extends="struts-default" namespace="/user">
.......
</package>
</struts>
二、拦截器
减少Action中的冗余代码,提高项目的可维护性。
1、开发 .java
实现interceptor接口
public String intercept(ActionInvocation ai) throws Exception {
// TODO Auto-generated method stub
System.out.println("------intercept------");
//请求放行 相当于过滤器中 chain.doFilter();
ai.invoke();
//跳转 强制登陆 跳转回登陆页面
return null;
}
2、配置
注意:拦截器中的返回值 return 应该如何配置
建议后续使用全局跳转进行配置!!!!!
3、拦截器栈
多个拦截器的冗余配置提取到拦截器栈中
4、默认拦截器配置
<!-- 本包中 所有的action都会被拦截器进行默认拦截 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
5、Struts中的拦截体系
一旦在Struts2中使用用户自定义拦截器,系统拦截器失效!
需要用户在使用拦截器的过程中手动添加系统拦截器。
<interceptors>
<interceptor name="loginInterceptor"
class="com.baizhi.interceptor.LoginInterceptor"></interceptor>
<interceptor-stack name="myStack">
<!-- 系统默认拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="loginInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
6、方法拦截器
针对Action中具体的方法名称
继承抽象类!!!
public class MyMethodInterceptor extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation ai) throws Exception {
System.out.println("----我是方法拦截器------");
ai.invoke();
return null;
}
}
配置
开发步骤
1、 实现拦截器
拦截器 实现interceptor接口 / 方法拦截器 继承 MethodFilterInterceptor
2、 配置
2.1 声明拦截器
2.2 配置拦截器栈 (添加系统默认拦截器)
2.3 可以使用全局跳转 以及 默认拦截器配置进行优化
三、文件下载
1、页面
<a href="${pageContext.request.contextPath}/downloadFile?
fileName=1.jpg&type=image/jpeg">下载图片</a>
fileName:需要下载的文件名称
type:下载的文件类型
2、Action
public class MyDownLoad extends ActionSupport {
private String fileName;
private String type; //类型的动态替换
private String saveFile;
//方法返回值???
//需要将文件返回给浏览器 通过流输入给浏览器
public InputStream getInputStream() throws FileNotFoundException{
String realPath =
ServletActionContext.getServletContext().getRealPath(saveFile);
return new FileInputStream(realPath+"/"+fileName);
}
}
注意:Struts2成员变量能做什么?
1.接收参数 2.替换request作用域代码简化传递
3.从struts.xml中读取数据 4.向Struts.xml中赋值数据
3、Struts.xml
<package name="download" extends="struts-default" namespace="/">
<!-- name = 访问路径 action标签中没有method属性 !!!! -->
<action name="downloadFile" class="com.baizhi.download.MyDownLoad">
<!--成员变量读取文件夹名称-->
<param name="saveFile">/file</param>
<!-- name可以不写 name=success 默认参数 -->
<!-- type :标识方法的返回值类型 stream: 指向 StreamResult -->
<result type="stream">
<!--通过成员变量赋值确定下载的文件类型 ${成员变量名称}-->
<param name="contentType">${type}</param>
<!-- contentDisposition 下载的数据保存类型 -->
<!--attachment 附件 inline 使用浏览器打开 -->
<param name="contentDisposition">attachment;filename=${fileName}
</param>
</result>
</action>
</package>
周末
登陆 / 注册 + 验证码 强制登陆 + 头像
展示数据,修改,删除
选做 展示时点击图片下载!!
Mvc思想: