文章目录
- Action与Servelet
- 使用 Servlet 相关API
- 接收参数
- 1.解耦合方式调用Servlet的API
- 2.耦合方式调用Servlet的API
- 3.ServletActionContext 静态获取(掌握)
- Action 请求参数的接收机制
- 属性驱动方式
- 模型驱动方式
- 复杂参数的封装
- 封装到 list
- 封装到 Map
- 请求参数的类型转换
- result结果集的使用(重点)
- 1. 局部结果集
- 2. 全局结果集
- 3. 结果集类型Type
- 请求跳转和重定向跳转的区别
- Struts2的文件的下载
- Struts2的文件下载的实现
- 请求参数校验机制
- 代码手动校验
- XML配置规则校验
- 拦截器机制(重点)
- Struts2原理(30课)了解
- 自定义登录拦截器
- Struts2的文件的上传
- Struts2的文件上传机制
Action与Servelet
接上文:struts2
https://blog.csdn.net/yp25805488/article/details/143142326?spm=1001.2014.3001.5501
使用 Servlet 相关API
struts2 默认情况下将 servlet api(比如:request 对象、response 对象、session 对象、application 对象)都隐藏起来了。但是在某些情况下,我们还需要调用 servlet api,比如,登录的时候将用户信息保存到 session 域中。Struts2 中提供了 3 种方式来获取 servlet 的 api
第一种方式:解耦方式获取:借助 ActionContext 获取,方便单元测试 Junit(这个是 struts2官方的推荐的方式,但是不利于理解,所以我们不推荐)
第二种方式:接口注入方式操作 Servlet API(了解)
第三种方式:通过 ServletActionContext 类的静态方法直接获取 Servlet API(掌握)
接收参数
1.解耦合方式调用Servlet的API
struts2为我们提供了一个API,可间接调用servlet api,这个api叫做:ActionContext 类 (Action 上下文 )。(可以理解该类就是一个工具类)该 API 提供大量间接操作 Servlet API 方法;
第一种,解耦方式:解耦方式获取:借助 ActionContext 获取,方便单元测试 Junit(这个是 struts2官方的推荐的方式,但是不利于理解,所以我们不推荐)
请求路径
访问链接http://localhost:8080/struts2_day02_chap01/indirect?name=admin
Action
package com.igeek_01_servletapi;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class IndirectServletAPIAction extends ActionSupport{/** * 访问链接http://localhost:8080/struts2_day02_chap01/indirect?name=admin */@Overridepublic String execute() throws Exception {//接收参数ActionContext context = ActionContext.getContext();Map<String, Object> params = context.getParameters();//接收的结果是一个数组?此处为什么要设计为数组接收页面参数?//因为通过数组的方式,如果页面传递的是一个值,数组也可以接收,//如果页面传递的是两个值,数组也可以接收String[] names = (String[]) params.get("name");System.out.println(names[0]);return NONE;}
}
2.耦合方式调用Servlet的API
接口:
ServletRequestAware – 获取到 request 对象
ServletResponseAware – 获取到 response 对象
ServletContextAware – 获取到 ServletContext 对象
第二种:耦合方式:接口注入方式操作 Servlet API(了解)
请求路径:通过实现接口获取request对象
Action
import javax.servlet.http.HttpServletRequest
import org.apache.struts2.interceptor.ServletRequestAware
import com.opensymphony.xwork2.ActionSupport;
public class InjectServletAPIAction extends ActionSupport implements ServletRequestAware{HttpServletRequest request;//自动设置ServletRequest 对象的方法 @Overridepublic void setServletRequest(HttpServletRequest arg0) {request = arg0;}/** * http://localhost:8080/struts2_day02_chap01/inject?name=admin*/@Overridepublic String execute() throws Exception {//获取参数String name = request.getParameter("name");System.out.println(name);request.setAttribute("msg", name); //返回参数到前端return SUCCESS;}
}
<body>${msg} //jsp获取参数
</body>
3.ServletActionContext 静态获取(掌握)
第三种:通过 ServletActionContext 类的静态方法直接获取 Servlet API(掌握)
package com.igeek_01_servletapi;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class DirectServletAPIAction extends ActionSupport{/** * http://localhost:8080/struts2_day02_chap01/direct?name=admin*/@Overridepublic String execute() throws Exception {HttpServletRequest request = ServletActionContext.getRequest();String name = request.getParameter("name");System.out.println(name);return NONE;}
}
Action 请求参数的接收机制
1、什么是请求参数?
答:比如登录、注册功能的时候,客户端需要向服务器提交登录或者注册信息,这些信息都是请求参数
Serlvet 接收参数:request.getParameter(“XXX”);
Struts2 提供两大类(属性驱动封装、模型驱动封装)、三种数据封装的方式:
属性驱动方式:
Action 本身作为表单 model 对象,通过成员变量的 setter 方法进行封装。(使用非常多)
Action 中创建独立的表单 model 对象和提供对应的 setter、getter 方法,页面通过ognl 表达式进行封装。
模型驱动方式:
使用 ModelDriven 接口(模型驱动),对请求的数据进行封装。(使用非常多)
属性驱动方式
Action 作为 model,通过成员变量属性和 setter 方法接 收参数进行封装(方式一)
public class LoginAction1 extends ActionSupport{//struts2框架自动接收参数// username:<input type="text" name="username"><br />// password:<input type="password" name="pwd"><br />//request.getParameter("username");private String username;private String pwd;//通过setter方法进行赋值public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String execute() throws Exception {System.out.println(toString());return NONE;}@Overridepublic String toString() {return "LoginAction1 [username=" + username + ", pwd=" + pwd + "]";}
}
Action 中创建独立的表单 model 对象和提供对应的 setter、getter 方法,页面通过ognl 表达式进行封装。
Model
package com.igeek.model;
public class UserInfo {private String username;private String pwd;public UserInfo() {System.out.println("userInfo的构造方法");}public String getUsername() {System.out.println("getUsername");return username;}public void setUsername(String username) {System.out.println("setUsername");this.username = username;}public String getPwd() {System.out.println("getPwd");return pwd;}public void setPwd(String pwd) {System.out.println("setPwd");this.pwd = pwd;}}
Action
package com.igeek_01_model;
import com.igeek.model.UserInfo;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction2 extends ActionSupport{private UserInfo userInfo ;public UserInfo getUserInfo() {System.out.println("getUserInfo");return userInfo;}public void setUserInfo(UserInfo userInfo) {System.out.println("setUserInfo");this.userInfo = userInfo;}@Overridepublic String execute() throws Exception {System.out.println(userInfo.getUsername()+"-->"+userInfo.getPwd());return NONE;}
}
jsp中表单提交参数 需要注意* userInfo.username 页面通过ognl 表达式进行封装
<form action="${pageContext.request.contextPath }/login2.action" method="post">username:<input type="text" name="userInfo.username" /><br>password:<input type="password" name="userInfo.pwd" /><br><input type="submit" value="登录" /></form>
模型驱动方式
使用 ModelDriven 接口(模型驱动),对请求的数据进行封装。(使用非常多)
创建 LoginAction3 类, 继承 ActionSupport 类,实现 ModelDriven 接口 ,实现getModel 方法
Action
package com.igeek_01_model;import com.igeek.model.UserInfo;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;/**
* @author jerry
* @version v1.0 2017年10月17日 上午11:09:02
*/
/**
* @ClassName: LoginAction3
* @Description: TODO(这里用一句话描述这个类的作用)
* @date 2017年10月17日 上午11:09:02
* Company www.igeekhome.com
*
*/
public class LoginAction3 extends ActionSupport implements ModelDriven</*接收Javabin的类型*/>{//必须初始化javabean对象private UserInfo user = new UserInfo();@Overridepublic UserInfo getModel() {System.out.println(user);return user;}@Overridepublic String execute() throws Exception {System.out.println(user.getUsername()+"-->"+user.getPwd());return NONE;}
}
复杂参数的封装
封装到 list
jsp提交参数格式
<form action="${ pageContext.request.contextPath }/product1Action.action" method="post">商品名称:<input type="text" name="list[0].name"/><br/>商品价格:<input type="text" name="list[0].price"/><br/>商品名称:<input type="text" name="list[1].name"/><br/>商品价格:<input type="text" name="list[1].price"/><br/>商品名称:<input type="text" name="list[2].name"/><br/>商品价格:<input type="text" name="list[2].price"/><br/><input type="submit" value="批量导入"/>
</form>
Model
package com.igeek.model;
public class Product {private String name;private double price;public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "Product [name=" + name + ", price=" + price + "]";}
}
Action
package com.igeek_01_model;
import java.util.List;
import com.igeek.model.Product;
import com.opensymphony.xwork2.ActionSupport;
public class ProductAction1 extends ActionSupport{private List<Product> list;public List<Product> getList() {return list;}public void setList(List<Product> list) {this.list = list;}@Overridepublic String execute() throws Exception {for (Product product : list) {System.out.println(product);}return NONE;}
}
封装到 Map
jsp提交参数格式
<form action="${ pageContext.request.contextPath }/productAction2.action" method="post">商品名称:<input type="text" name="map['one'].name"/><br/>商品价格:<input type="text" name="map['one'].price"/><br/>商品名称:<input type="text" name="map['two'].name"/><br/>商品价格:<input type="text" name="map['two'].price"/><br/>商品名称:<input type="text" name="map['three'].name"/><br/>商品价格:<input type="text" name="map['three'].price"/><br/><input type="submit" value="批量导入"/>
</form>
Model
package com.igeek.model;
public class Product {private String name;private double price;public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "Product [name=" + name + ", price=" + price + "]";}
}
Action
package com.igeek_01_model;
import java.util.Map;
import com.igeek.model.Product;
import com.opensymphony.xwork2.ActionSupport;
public class ProductAction2 extends ActionSupport{private Map<String, Product> map;public Map<String, Product> getMap() {return map;}public void setMap(Map<String, Product> map) {this.map = map;}@Overridepublic String execute() throws Exception {for (String key : map.keySet()) {Product p = map.get(key);System.out.println(p);}return NONE;}
}
请求参数的类型转换
Struts2 内置了常见数据类型多种转换器,如下:
boolean 和 Boolean
char 和 Character
int 和 Integer
long 和 Long
float 和 Float
double 和 Double
Date 可以接收 yyyy-MM-dd 格式字符串
数组 可以将多个同名参数,转换到数组中
集合 支持将数据保存到 List 或者 Map 集合
编写注册案例 (包含文本、数字、日期、数组)
jsp提交页面格式
<form action="${pageContext.request.contextPath }/regist.action" method="post">username:<input type="text" name="username"><br />age:<input type="text" name="age"><br /> <h1>日期格式默认使用 yyyy-MM-dd</h1> birthday:<input type="text" name="birthday"><br />hobby:<input type="checkbox" name="hobby" value="音乐">音乐<input type="checkbox" name="hobby" value="游戏">游戏<input type="checkbox" name="hobby" value="旅游">旅游<br /><input type="submit" value="注册">
</form>
Action
package com.igeek.conversion;
import java.util.Arrays;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;public class RegistAction extends ActionSupport{private String username;private int age;private Date birthday;private String[] hobby;//getter and setter......@Overridepublic String toString() {return "RegistAction [username=" + username + ", age=" + age + ", birthday=" + birthday + ", hobby="+ Arrays.toString(hobby) + "]";}@Overridepublic String execute() throws Exception {System.out.println(toString());return NONE;}
}
result结果集的使用(重点)
结果集:可以把它看成是响应,通过配置方式实现页面路径的跳转
1. 局部结果集
局部结果:一个Action只能对应着 一个结果
Action
package com.igeek.result;
import com.opensymphony.xwork2.ActionSupport;
public class LocalResultAction extends ActionSupport{@Overridepublic String execute() throws Exception {System.out.println("LocalResultAction");return SUCCESS;}
}
struts.xml
<!--局部结果集,result配置在Action节点中,针对当前action有效 --><action name="local" class="com.igeek.result.LocalResultAction"><!-- result name="success" 可以省略 name="success" --><result>/local_result.jsp</result></action>
2. 全局结果集
全局结果:多个Action都可以跳到 一个结果 progect: struts2_day02_chap04
Action
package com.igeek.result;import com.opensymphony.xwork2.ActionSupport;
public class GlobalResultAction extends ActionSupport{@Overridepublic String execute() throws Exception {System.out.println("GlobalResultAction");return SUCCESS;}
}
sturts.xml
<!-- 配置全局结果集, global-results必须配置在action节点前-->
<global-results><result>/global_result.jsp</result>
</global-results><!-- 不配置result节点,会使用global-results节点 -->
<action name="global" class="com.igeek.result.GlobalResultAction"></action>-----progect: struts2_day02_chap04
3. 结果集类型Type
作用:控制响应的方式(转发、重定向)配置 元素时, name 是逻辑视图名称, type 是结果集类型。Struts2 提供的常用结果集类型都定义在 struts-default.xml 中:
type=“dispatcher” 是forword转发,默认值,可以不写
<result type="dispatcher">/result_type1.jsp</result>-
使用chain跳转到另一个action,是forword转发
<result type="chain">r2</result>
使用redirect重定向jsp页面
<result type="redirect">/result_type1.jsp</result>
使用redirect重定向到action
<result type="redirectAction">r2</result>
请求跳转和重定向跳转的区别
Action1
package com.igeek.result;
import com.opensymphony.xwork2.ActionSupport;
public class ResultType1Action extends ActionSupport{@Overridepublic String execute() throws Exception {System.out.println("ResultType1Action");return SUCCESS;}
}
Action2
package com.igeek.result;
import com.opensymphony.xwork2.ActionSupport;
public class ResultType2Action extends ActionSupport{@Overridepublic String execute() throws Exception {System.out.println("ResultType2Action");return SUCCESS;}
}
struts.xml
<action name="r1" class="com.igeek.result.ResultType1Action"><!--type="dispatcher" 是forword转发,默认值,可以不写 --><result type="dispatcher">/result_type1.jsp</result> 地址栏没有发生变化<!-- 使用chain跳转到另一个action,是forword转发 --> <result type="chain">r2</result> 地址栏没有发生变化 但页面成功跳转<!-- 使用redirect重定向jsp页面 --><result type="redirect">/result_type1.jsp</result> 地址栏发生变化<!-- 使用redirect重定向到action --><result type="redirectAction">r2</result> 地址栏发生变化 页面跳转成功</action><!-- r2 另外一个页面 -->
<action name="r2" class="com.igeek.result.ResultType2Action"><result>/result_type2.jsp</result>
</action>
【总结】
dispatcher(默认值):请求转发。(最常用)
作用:服务器内部是同一次请求,可采用 request 传递数据,URL 不变,forword 方式跳转到 jsp 页面
chain(了解)
作用:请求转发到另外一个 Action 中,forword 方式跳转到另一个 action
redirect
作用:重定向到某个 jsp 页面,服务器发起了一次新的请求,不能通过 request 传递参数,URL 改变为新的地址。应用场景举例:登录后重定向到网站的主页面,注销用户是重定向到登录页面。重定向到 jsp 页面。
redirectAction
作用:重定向到另外一个 Action
Struts2的文件的下载
要点:两头一流 progect: struts2_day02_chap05
使用 response 输出流,将文件信息打印到客户端
设置 Content-Type 头信息, 通过ServletActionContext.getServletContext().getMimeType(fileName); 获取
设置 Content-Disposition 头信息 , attachment;filename=文件名
Struts2的文件下载的实现
Action
package com.igeek.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.igeek.utils.FileUtils;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class DownloadAction extends ActionSupport{@Overridepublic String execute() throws Exception {//指定下载路径String path="d://";String filename = "你好.txt";//获取两头一流//文件类型String contentType = ServletActionContext.getServletContext().getMimeType(filename);//输入流InputStream inputStream = new FileInputStream(new File(path+filename));//content-disposition//处理文件名的中文乱码 agent 浏览器类型String agent = ServletActionContext.getRequest().getHeader("user-agent");//处理后的文件名filename = FileUtils.encodeDownloadFilename(filename, agent);String contentDisposition = "attachment;filename="+filename;//把上面的3个信息放入值栈(容器)//文件类型ActionContext.getContext().put("contentType", contentType);//流ActionContext.getContext().put("inputStream", inputStream);//对应的文件名ActionContext.getContext().put("contentDisposition", contentDisposition);return SUCCESS;}
}
文件编码问题处理工具类
package com.igeek.utils;import java.io.IOException;
import java.net.URLEncoder;import sun.misc.BASE64Encoder;public class FileUtils {/*** 下载文件时,针对不同浏览器,进行附件名的编码* @param filename下载文件名* @param agent 客户端浏览器* @return 编码后的下载附件名* @throws IOException*/public static String encodeDownloadFilename(String filename, String agent)throws IOException {if (agent.contains("Firefox")) { // 火狐浏览器filename = "=?UTF-8?B?"+ new BASE64Encoder().encode(filename.getBytes("utf-8"))+ "?=";filename = filename.replaceAll("\r\n", "");} else { // IE及其他浏览器filename = URLEncoder.encode(filename, "utf-8");filename = filename.replace("+"," ");}return filename;}
}
struts.xml
<package name="default" extends="struts-default" namespace="/"><!-- 配置下载的Action --><action name="download" class="com.igeek.download.DownloadAction"><!-- 使用struts2提供的下载功能,需要配置结果集类型为stream --><result type="stream"></result></action>
</package>
请求参数校验机制
请求参数的输入校验途径一般分两种:
客户端校验 :通过 JavaScript 完成 (jquery validation 插件),目的:过滤正常用户的误操作。
服务器校验 :通过 java 代码完成 ,目的:整个应用阻止非法数据的重要防线/最后防线两者校验的特点:客户端校验,更加友好, 用户可以第一时间告知数据输入有错误(缺点:安全性差), 服务器校验 更加安全校验机制 (考虑系统健壮性 ,服务器校验建议要做)
我们这里研究的是:在请求数据封装之后, 在 struts2 实现请求数据合法性校验。
代码手动校验
有两种校验范围:
全局校验 (对当前 Action 的所有方法进行校验 )在 Action 提供 validate() 方法 — 对 Action 中所有的方法都进行校验
局部校验 (校验 Action 中指定业务方法—校验一个方法 )在 Action 添加 validateXxx 方法(约定), 这里 XXX 是要校验目标方法名 (只会对指定方法校验) 方法名首字母大写
提示:
1.局部校验被校验方法首字母 要大写。
2.全局校验一定会执行,如果出现局部校验。先执行的局部校验,再执行全局校验。
【注意点】
你的局部校验和全局校验不能同时对同一个表单内容进行矛盾的校验
局部校验:age:18--30
全局校验:age:40--50
jsp提交参数
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %> --- 标记库 使用<s:fielderror/> 需要添加
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'login.jsp' starting page</title></head><body><h3>登录:请求数据校验--代码手动校验</h3><!--s:fielderror 用于显示错误信心的struts2标签 --><s:fielderror/><form action="${pageContext.request.contextPath }/user_login.action" method="post">用户名:<input type="text" name="username"/><br/>密 码:<input type="password" name="pwd"/><br/><input type="submit" value="登录"/></form></body>
</html>
Action
package com.igeek_01_validation;
import org.apache.commons.lang3.StringUtils;
import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport{//1.接收用户名和密码private String username;private String pwd;public String login() throws Exception {System.out.println(username+"-->"+pwd);return NONE;}public String find() throws Exception {System.out.println(username);return NONE;}//校验 ActionSupport 提供了一个校验功能//input: 校验出错后会自动跳转到input对应的视图/** * 全局校验 校验所有方法*/@Override public void validate() {//编写校验的逻辑代码,程序运行时会自动调用validate方法进行校验if(StringUtils.isBlank(username)){//添加提示信息//addFieldError 会把错误信息放入一个集合,在页面上通过s:fielderror 标签获取集合中的内容,//在页面上显示错误信息addFieldError("username_error", "用户名不能为空...");}if(StringUtils.isBlank(pwd)){addFieldError("pwd_error", "密码不能为空...");}}/**局部校验*///只校验login方法public void validateLogin() {//编写校验的逻辑代码,程序运行时会自动调用validate方法进行校验if(StringUtils.isBlank(username)){//添加提示信息//addFieldError 会把错误信息放入一个集合,在页面上通过s:fielderror 标签获取集合中的内容,//在页面上显示错误信息addFieldError("username_error", "用户名不能为空...");}if(StringUtils.isBlank(pwd)){addFieldError("pwd_error", "密码不能为空...");}}//getter...settter....
}
input: 校验出错后会自动跳转到input对应的视图(全局校验)
<!-- 配置mylogin.action -->
<action name="mylogin" class="com.igeek_01_validation.MyLoginAction"><result>/a_validation/succ.jsp</result><!--验证出错跳转视图 input --><result name="input">/a_validation/mylogin.jsp</result>
</action>
XML配置规则校验
手动代码校验,不适用于表单元素非常多情况,造成代码量很大,且不容易维护(代码耦合性太强!!!)。企业中一般推荐使用xml文件来配置表单校验。
执行xml配置校验的要求:Action 必须继承ActionSupport类(为了实现Validateable接口)。
这里根据校验规则生效的范围分为全局校验和局部校验两种。–跟手动校验的两种方式是对应的
全局校验:对Action中的所有的方法都生效
局部校验:对Action中的某个方法生效
全局校验
<body><s:fielderror></s:fielderror><form action="${pageContext.request.contextPath }/mylogin.action" method="post">用户名:<input type="text" name="username"><br/>密 码:<input type="password" name="pwd"><br/><input type="submit" value="登录"></form>
</body>
Action
package com.igeek_01_validation;import com.opensymphony.xwork2.ActionSupport;public class MyLoginAction extends ActionSupport{private String username;private String pwd;@Overridepublic String execute() throws Exception {System.out.println(username+"-->"+pwd);return SUCCESS;}//getter 。。。。。。。。。
}
struts.xml
<!-- 配置mylogin.action -->
<action name="mylogin" class="com.igeek_01_validation.MyLoginAction"><result>/a_validation/succ.jsp</result><!--验证出错跳转视图 input --><result name="input">/a_validation/mylogin.jsp</result>
</action>
全局性的校验文件:直接是 Action的名字-validation.xml
文件写在Action的同目录下
MyLoginAction-validation.xml 新建校验文件
<?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><!-- 要验证的input框name属性 --><field name="username"><!--验证类型 有很多种,可以搜索struts验证类型 --><field-validator type="requiredstring"><!-- 配置校验器参数 【示例】如果你将trim的值设置为false的时候,校验的时候,不去除空格--><param name="trim">false</param><!-- 显示校验出错信息 --><message>请输入用户名</message></field-validator></field><field name="pwd"><field-validator type="requiredstring"><message>请输入密码</message></field-validator></field>
</validators>
局部校验
区别:作用域范围:校验当前Action的指定方法。
编写xml的方法:在Action类所在包,创建类名-URL访问路径-validation.xml
jsp提交的参数
<body><s:fielderror /><form action="${pageContext.request.contextPath }/myRegist.action" method="post">username:<input type="text" name="username">(非空,且长度为3-10位)<br>password:<input type="password" name="pwd">(必须,且长度为6-12)<br>repwd:<input type="password" name="repwd">(必须和密码一致)<br>age:<input type="text" name="age"> (年龄在18-90之间)<br>phone:<input type="text" name="phone">(手机号规则,11位数字)<br>email:<input type="text" name="email">(邮箱格式)<br><input type="submit" value="注册"></form></body>
Action
package com.igeek_01_validation;import com.opensymphony.xwork2.ActionSupport;public class MyRegistAction extends ActionSupport{private String username;private String pwd;private String repwd;private int age;private String phone;private String email;public String regist() throws Exception {System.out.println(toString());return NONE;}。。。。。。getter..
}
struts,xml
<!-- 注册Action -->
<action name="myRegist" class="com.igeek_01_validation.MyRegistAction" method="regist"><result name="input">/a_validation/myRegist.jsp</result>
</action>
校验文件 类名-URL访问路径-validation.xml
MyRegistAction-myRegist-validation.xml
<?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>
<!--username:<input type="text" name="username">(非空,且长度为3-10位)<br> --><field name="username"><field-validator type="requiredstring"><message>用户名不能为空</message></field-validator><field-validator type="stringlength"><param name="minLength">3</param><param name="maxLength">10</param><message>用户名长度为3到10位</message></field-validator></field><!-- password:<input type="password" name="pwd">(必须,且长度为6-12)<br> --><field name="pwd"><field-validator type="requiredstring"><message>密码不能为空</message></field-validator><field-validator type="stringlength"><param name="minLength">6</param><param name="maxLength">12</param><message>密码长度为6到12位</message></field-validator></field><!-- repwd:<input type="password" name="repwd">(必须和密码一致)<br> --><field name="repwd"><field-validator type="fieldexpression"><param name="expression"><![CDATA[pwd==repwd]]></param><message>两次输入的密码必须一致</message></field-validator></field><!-- age:<input type="text" name="age"> (年龄在18-90之间)<br> --><field name="age"><field-validator type="int"><param name="min">18</param><param name="max">90</param><message>年龄在18-90之间</message></field-validator></field><!-- phone:<input type="text" name="phone">(手机号规则,11位数字)<br> --><field name="phone"><field-validator type="regex"><param name="regex"><![CDATA[^\d{11}$]]></param><message>手机号规则,11位数字</message></field-validator></field><!--email:<input type="text" name="email">(邮箱格式)<br> --><field name="email"><field-validator type="email"><message>请填写正确的邮箱格式</message></field-validator></field>
</validators>
拦截器机制(重点)
拦截器就是一个类,它能够拦截Action的请求,并进行预处理。
Struts2 拦截器在访问某个Action 方法之前或之后实施拦截,(在action之前调用的称之为前置拦截器,之后也称之为后置拦截器)
拦截器是可插拔的,是一种AOP 实现
aop思想简单理解:在不改变原来代码的情况下,对原来的代码功能进行控制和增强(增加或减少)
Action
package com.igeek.action_01;
import com.opensymphony.xwork2.ActionSupport;
public class MyAction extends ActionSupport{@Overridepublic String execute() throws Exception {System.out.println("执行了MyAction");return NONE;}
}
拦截器配置类 MyInterceptor
package com.igeek.action_01;import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor implements Interceptor{@Overridepublic void destroy() {// TODO Auto-generated method stub}@Overridepublic void init() {// TODO Auto-generated method stub}@Overridepublic String intercept(ActionInvocation invocation) throws Exception {//方法之前去执行System.out.println("begin method");//调用Action中的execute方法,返回执行execute方法的字符串String result = invocation.invoke();System.out.println(result);//方法之后去执行System.out.println("after method");return result;}
}
struts.xml配置
<!-- 注册自定义的拦截器 -->
<interceptors><!-- 给自定义的拦截器起一个名字name--><interceptor name="myCeptor" class="com.igeek.action_01.MyInterceptor"></interceptor>
</interceptors><action name="myAction" class="com.igeek.action_01.MyAction"><!-- 使用自定义的拦截器,这种配置方式,会把默认的拦截器去掉,只留自定义的拦截器 -->如果配置了自定义拦截器,那么使用自定义的拦截器,不会使用默认的的18个拦截器结论:我们实际开发过程中,不能只配置一个自定义的拦截器--><interceptor-ref name="myCeptor"></interceptor-ref>
</action>
拦截器和过滤器的区别
struts2的2.1.6这个版本以前,核心控制器是FilterDispatcher,从2.1.6开始,使用是StrutsPrepareAndExecuteFilter)
Struts2原理(30课)了解
拦截器的接口*
程序中每个拦截器都必须实现Interceptor 接口
开发人员也可以继承AbstractInterceptor 只需要覆盖intercept 方法
开发人员也可以继承MethodFilterInterceptor ,只需要覆盖doIntercept 方法
excludeMethods 放行的方法(不去拦截的方法)
includeMethods 包含的方法(拦截的方法)
自带的拦截器
自定义登录拦截器
【业务目标】:登录拦截:如果未登录,则无法访问到业务相关的action
【具体描述】:项目中提供三个页面:login.jsp,addbook.jsp,addbooksuccess.jsp,启动项目的时候,直接进入login.jsp,用户进行登录,如果登录信息正确,则可以进入bookadd.jsp页面,进行信息的添加;如果登录失败,则返回login.jsp,并且提示相关信息;对于bookadd.jsp 的提交功能,必须要在登录成功之后,才可以添加成功,如果没有登录,是无法进入的,这里采用拦截器进行拦截,从session中获取user信息进行判断。
登录的jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'login.jsp' starting page</title></head><body><s:fielderror /><h3>登录界面</h3> <form action="${pageContext.request.contextPath }/interceptor/user_login.action" method="post">username:<input type="text" name="username"><br>password:<input type="password" name="pwd"><br><input type="submit" value="提交"></form></body>
</html>
书籍添加的jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'bookadd.jsp' starting page</title></head> <body><h3>书籍信息添加页面</h3> <form action="${pageContext.request.contextPath }/interceptor/book_add.action" method="post">bookname:<input type="text" name="bookname"><br>price:<input type="text" name="price"><br><input type="submit" value="提交"></form></body>
</html>
添加成功的jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>This is my book add success JSP page. <br>
</body>
</html>
UserAction
package com.igeek.action_01;import org.apache.struts2.ServletActionContext;import com.igeek.model.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;public class UserAction extends ActionSupport implements ModelDriven<User>{、//手动初始化private User user = new User();//ModelDriven重写 @Overridepublic User getModel() {return user;}public String login() throws Exception {//用户名为admin,密码为123456if(user.getUsername().equals("admin") && user.getPwd().equals("123456")){//把用户信息放入sessionServletActionContext.getRequest().getSession().setAttribute("user", user);return SUCCESS;}else{addFieldError("user_error", "用户名或密码不正确");//跳转到登录页面return INPUT;}}
}
BookAction
package com.igeek.action_01;
import com.igeek.model.Book;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;public class BookAction extends ActionSupport implements ModelDriven<Book>{private Book book = new Book();public String add() throws Exception {System.out.println(book.toString());return SUCCESS;}@Overridepublic Book getModel() {return book;}
}
Model - User
package com.igeek.model;
//用户模型
public class User {//用户名private String username;//密码private String pwd;//getter。。。。。
}
Model-Book
package com.igeek.model;public class Book {
// 书名private String bookname;
// 价格private double price;//getter。。。。。
}
struts.xml (重要)
<!-- 配置拦截器 --><package name="myInterceptor" extends="struts-default" namespace="/interceptor"><!-- 注册自定义的拦截器 -->1.<interceptors><interceptor name="bookCeptor" class="com.igeek.action_01.MyBookInterceptor"><!-- 登录的方法放行呢?excludeMethods:放行的方法:includeMethods:只拦截的方法--><param name="excludeMethods">login</param></interceptor>2.<!-- 如果要用框架和自定义的拦截器,我们可以定义一个拦截器栈 --><interceptor-stack name="myStack"><interceptor-ref name="bookCeptor"></interceptor-ref><interceptor-ref name="defaultStack"></interceptor-ref></interceptor-stack></interceptors>3. <!-- 告诉系统使用自定义的拦截器栈 --><default-interceptor-ref name="myStack"></default-interceptor-ref>
------------------------------------------------------------------------------------ <!-- 定义一个全局结果集来处理未登录情况 --><global-results><result name="no_login">/a_interceptor/login.jsp</result></global-results><!--登录的Action --><action name="user_*" class="com.igeek.action_01.UserAction" method="{1}"><result>/a_interceptor/addbook.jsp</result><result name="input">/a_interceptor/login.jsp</result></action><!-- BookAction --><action name="book_*" class="com.igeek.action_01.BookAction" method="{1}"><result>/a_interceptor/addbooksuccess.jsp</result></action></package>
拦截器
package com.igeek.action_01;
import org.apache.struts2.ServletActionContext;
import com.igeek.model.User;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;public class MyBookInterceptor extends MethodFilterInterceptor{@Overrideprotected String doIntercept(ActionInvocation invocation) throws Exception {//判断session中是否有用户存在User user =(User) ServletActionContext.getRequest().getSession().getAttribute("user");if(user == null){//未登录//添加提示信息ActionSupport action = (ActionSupport) invocation.getAction();action.addFieldError("login_error", "请登录后再操作");return "no_login";}else{//执行actionreturn invocation.invoke();}}}
Struts2的文件的上传
原理:服务端需要接收文件类型、文件名、文件大小
Struts2的文件上传机制
Struts2 内部文件上传,默认采用apachecommons-fileupload Struts2 默认导入文件上传jar包
defaultStack 默认拦截器栈,提供fileUpload的拦截器,用于实现文件上传
文件上实例
jsp前端页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>My JSP 'upload.jsp' starting page</title></head><body><s:fielderror></s:fielderror><form action="${pageContext.request.contextPath }/upload.action" method="post" enctype="multipart/form-data"><input type="file" name="upload1"><br><input type="submit" value="提交"></form></body>
</html>
Action
package com.igeek_01_upload;
import java.io.File;
import org.apache.commons.io.FileUtils;
import com.opensymphony.xwork2.ActionSupport;
*/
public class UploadAction extends ActionSupport{/*** 需要3个参数*/private File upload1;//与input框的name属性对应 <input type="file" name="upload1"><br>private String upload1ContentType;//upload1+ContentTypeprivate String upload1FileName;//upload1+FileNamepublic File getUpload1() {return upload1;}public void setUpload1(File upload1) {this.upload1 = upload1;}public String getUpload1ContentType() {return upload1ContentType;}public void setUpload1ContentType(String upload1ContentType) {this.upload1ContentType = upload1ContentType;}public String getUpload1FileName() {return upload1FileName;}public void setUpload1FileName(String upload1FileName) {this.upload1FileName = upload1FileName;}@Overridepublic String execute() throws Exception {//一句话搞定文件上传FileUtils.copyFile(upload1, new File("d://"+upload1FileName));return SUCCESS;}
}
struts.xml
<!-- 配置读取国际化信息常量 提示中文字符 --><constant name="struts.custom.i18n.resources" value="messages"></constant><!-- 通过配置常量来限制上传文件的大小 --><constant name="struts.multipart.maxSize" value="10000000"></constant>
-------------------------------------------------------------------------------------------------------------------<package name="default" extends="struts-default" namespace="/"><!-- 配置上传Action --><action name="upload" class="com.igeek_01_upload.UploadAction"><result name="input">/b_upload/upload.jsp</result><!-- 配置文件上传参数 --><interceptor-ref name="defaultStack"><!-- 限制上传文件大小 --><param name="fileUpload.maximumSize">2097152</param><param name="fileUpload.allowedExtensions">.txt</param></interceptor-ref></action></package>
文件上传错误后的提示信息怎么转换为中文
包下添加 messages.properties 文件
struts.messages.error.file.extension.not.allowed=\u8BF7\u4E0A\u4F20\u6B63\u786E\u7684\u6587\u4EF6\u7C7B\u578B: {0} "{1}" "{2}" {3}