Java进阶学习第十七天(Struts框架:拦截器、国际化、OGNL表达式语言)

版权声明:使用本品须Jack Gao同意,违者必究 https://blog.csdn.net/Mr_GaoYang/article/details/82743911

一、拦截器(Intercetor)

1、概述
① 在Struts2中,把每一个功能都用一个个的拦截器实现;用户想用struts的哪个功能的时候,可以自由组装使用。
② Struts2中,为了方法用户对拦截器的引用,提供了拦截器栈的定义,里面可以包含多个拦截器。和文件夹(文件1,文件2)结构类似:拦截器栈(拦截器1,拦截器2)
③ Struts2中,如果用户没有指定执行哪些拦截器,struts2有一个默认执行的栈,defaultStack;一旦如果用户有指定执行哪些拦截器,默认的拦截器栈就不会被执行

2、拦截器配置
struts-default.xml文件中,定义了struts提供的所有拦截器!

//1. 定义拦截器以及拦截器栈
<interceptors>
    1.1 拦截器定义
    <interceptor name="" class="" /> 
    1.2 拦截器栈的定义
    <interceptor-stack name="defaultStack">
	引用了上面拦截器(1.1)
    </interceptor-stack>
</interceptors>

3、默认执行的拦截器(栈)
<default-interceptor-ref name="defaultStack"/>
API:
① Interceptor 拦截器接口
◆A bstractInterceptor 拦截器默认实现的抽象类; 一般用户只需要继承此类即可继续拦截器开发
② ActionInvocation 拦截器的执行状态,调用下一个拦截器或Action

4、自定义一个拦截器案例
步骤:写拦截器类 (看生命周期),然后配置

public class HelloInterceptor implements Interceptor{
	// 启动时候执行
	public HelloInterceptor(){
		System.out.println("创建了拦截器对象");
	}
	// 启动时候执行
	@Override
	public void init() {
		System.out.println("执行了拦截器的初始化方法");
	}
	// 拦截器业务处理方法 (在访问action时候执行? 在execute之前执行?)
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("2. 拦截器,业务处理-开始");
		// 调用下一个拦截器或执行Action  (相当于chain.doFilter(..)
		// 获取的是: execute方法的返回值
		String resultFlag = invocation.invoke();
		System.out.println("4. 拦截器,业务处理-结束");
		return resultFlag;
	}
	@Override
	public void destroy() {
		System.out.println("销毁....");
	}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
	<package name="hello" extends="struts-default">
		<!-- 【拦截器配置】 -->
		<interceptors>
			<!-- 配置用户自定义的拦截器 -->
			<interceptor name="helloInterceptor" class="cn.itcast.a_interceptor.HelloInterceptor"></interceptor>
			<!-- 自定义一个栈: 要引用默认栈、自定义的拦截器 -->
			<interceptor-stack name="helloStack">
				<!-- 引用默认栈 (一定要放到第一行)-->
				<interceptor-ref name="defaultStack"></interceptor-ref>
				<!-- 引用自定义拦截器 -->
				<interceptor-ref name="helloInterceptor"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		<!-- 【执行拦截器】 -->
		<default-interceptor-ref name="helloStack"></default-interceptor-ref>
		<!-- Action配置 -->
		<action name="hello" class="cn.itcast.a_interceptor.HelloAction">
			<result name="success"></result>
		</action>
	</package>
</struts>

5、拦截器执行流程
拦截器执行流程
① 启动:创建所有拦截器、执行init()
② 访问:先创建Action,再执行拦截器,最后拦截器放行,执行execute()

6、拦截器案例
需求:登陆后,显示列表!
案例准备:Struts jar文件、DbUtils组件、数据库连接池/ 驱动包

① login.jsp

<body>
  	 <form method="post" action="${pageContext.request.contextPath }/user_login.action">
  	 	用户名:<input type="text" name="admin.userName"><br/>
  	 	密码:<input type="text" name="admin.pwd"><br/>
  	 	<input type="submit" value="登陆"><br/>
  	 </form>
</body>

② UserAction.java

public class UserAction extends ActionSupport {
	// ---------1. 封装请求数据-----------
	private Admin admin;
	public Admin getAdmin() {
		return admin;
	}
	public void setAdmin(Admin admin) {
		this.admin = admin;
	}
	// ---------2. 调用的Service-----------
	private AdminService adminService = new AdminService();
	// 登陆
	public String login() {
		try {
			Admin userInfo = adminService.login(admin);
			// 判断
			if (userInfo == null){
				// 登陆失败
				return "input";
			}
			// 登陆成功:数据保存在session中
			ActionContext.getContext().getSession().put("userInfo", userInfo);
			// 登陆成功
			return "loginSuccess";
		} catch (Exception e) {
			return ERROR;
		}
	}
	// 列表
	public String list() {
		try {
			// 查询全部
			List<Admin> list = adminService.getAll();
			// 保存到request
			ActionContext.getContext().getContextMap().put("listAdmin", list);
			return "list";
		} catch (Exception e) {
			return ERROR;
		}
	}
	public String add() {
		return null;
	}
}

③ list.jsp

<body>
  	<h1>欢迎你,${userInfo.userName }</h1>
  	<table align="center" border="1">
  		<tr>
  			<td>序号</td>
  			<td>编号</td>
  			<td>用户名</td>
  			<td>密码</td>
  		</tr>
  		<%--@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" --%>
  		
  		<!-- 用struts标签迭代数据 -->
  		<%@taglib uri="/struts-tags" prefix="s" %>
  		<s:iterator var="admin" value="#request.listAdmin" status="st">
  			<tr>
  				<td>
  					<s:property value="#st.count"/>
  				</td>
  				<td>
  					<s:property value="#admin.id"/>
  				</td>
  				<td>
  					<s:property value="#admin.userName"/>
  				</td>
  				<td>
  					<s:property value="#admin.pwd"/>
  				</td>
  			</tr>
  		</s:iterator>
  	</table>
  </body>

④ 自定义拦截器

public class UserCheckInterceptor extends AbstractInterceptor{
	/**
	 * 拦截器业务处理方法
	 */
	public String intercept(ActionInvocation invocation) throws Exception {
		// 拿到当前执行的方法名:判断,只有当前方法名不是login,就进行验证
		// 获取ActionContext对象
		ActionContext ac = invocation.getInvocationContext();
		// 获取action的代理对象
		ActionProxy proxy = invocation.getProxy();
		// 获取当前执行的方法名
		String methodName = proxy.getMethod();
		// 判断
		if (!"login".equals(methodName)) {
			 // 先获取当前登陆的用户
			 Object obj = ac.getSession().get("userInfo");
			 if (obj == null) {
				 // 没有登陆
				 return "input";
			 } else {
				 // 当前用户有登陆
				 return invocation.invoke();
			 }
		 } else {
			 // 说明当前用户正在登陆
			 return invocation.invoke();
		 }
	}
}

⑤ 配置拦截器

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
	<package name="user" extends="struts-default">
		<!-- 【拦截器配置】 -->
		<interceptors>
			<interceptor name="loginCheck" class="cn.itcast.interceptor.UserCheckInterceptor"></interceptor>
			<interceptor-stack name="myStack">
				<interceptor-ref name="defaultStack"></interceptor-ref>
				<interceptor-ref name="loginCheck"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		
		<!-- 【执行拦截器:第一种写法: 当前包下所有的acntion都执行myStack栈】
		<default-interceptor-ref name="myStack"></default-interceptor-ref>
		 -->
		<!-- 全局配置 -->
		<global-results>
			<result name="error">/error.jsp</result>
		</global-results>
		
		<action name="user_*" class="cn.itcast.action.UserAction" method="{1}">
			<!--第二种写法: 只是在这一个Action中执行myStack栈 
			<interceptor-ref name="defaultStackt"></interceptor-ref>
			<interceptor-ref name="loginCheck"></interceptor-ref>
			-->
			
			<!-- 第三种写法:执行用户栈(与第二种写法一样,只在当前aciton中执行自定义栈) -->
			<interceptor-ref name="myStack"></interceptor-ref>
			
			<!-- 1. 登陆失败 -->
			<result name="input">/login.jsp</result>
			<!-- 2. 登陆成功 -->
			<result name="loginSuccess" type="redirectAction">user_list</result>
			<!-- 3. 列表展示 -->
			<result name="list">/WEB-INF/list.jsp</result>
		</action>
	</package>
</struts>

二、Struts2中的国际化

1、Servlet 中国际化:
① 写资源文件
基础名.properties 【默认的语言环境的配置】
基础名_语言简称_国家简称.properties
② 读取资源文件,再使用
◆ 程序:ResourceBundle
◆ Jsp:jstl提供的格式化与国际化标签库。

2、Struts2中国际化
① 写资源文件 (同servlet)
② 读资源文件
◆ 程序:ResourceBundle (同servlet)
◆ JSP:jstl表亲啊(同servlet)、struts标签获取资源文件内容

3、区别:Struts2加载资源文件更加简单!通过常量加载即可!再在jsp页面直接使用!

4、过程

① 写资源文件

Msg.properties   默认的语言环境; 找不到配置就找它
Msg_en_US.properties  美国

② 加载

<constant name="struts.custom.i18n.resources" value="cn.itcast.config.msg"></constant>

③ 使用:标签name值直接写配置文件中的key

<s:text name="title"></s:text>

5、【推荐】加载资源文件通过常量加载,
还可以在页面加载:

<s:i18n name="cn.itcast.config.msg">
	<s:text>  标签必须放到标签体中
</s:i18n>

三、OGNL表达式语言

1、OGNL表达式
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

2、OGNL优势
① 支持对象方法调用,如xxx.doSomeSpecial();
② 支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名]
例如:
@java.lang.String@format('foo %s', 'bar')
@tutorial.MyConstant@APP_NAME
③ 支持赋值操作和表达式串联,如price=100, discount=0.8, calculatePrice(),这个表达式会返回80;
④ 访问OGNL上下文(OGNL context)和ActionContext;
⑤ 操作集合对象。

3、总结
OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了 java.utils.Map 的接口。 也就是OgnlContext对象,是OGNL的核心。

4、分析:Struts框架默认就支持Ognl表达式语言(struts必须引用的包:ognl.jar)

5、作用:页面取值用
El表达式语言,用于页面取值,jsp页面取值的标准(默认直接可以使用)
(应用范围更广)
Ognl表达式语言, struts标签默认支持的表达式语言。必须配置struts标签用,不能离开struts标签直接用。

6、OgnlContext对象(了解)
OgnlContext对象是ognl表达式语言的核心。
源码类:
public class OgnlContext extends Object implements Map{..}

通过硬编码方式,了解OgnlContext对象

// OgnlContext用法
public class OgnlDemo1 {
	/**
	 * 1. Ognl表达式语言语言取值,取非根元素的值,必须用#号
	 * @throws Exception
	 */
	@Test
	public void testOgnl() throws Exception {
		// 创建一个Ognl上下文对象
		OgnlContext context = new OgnlContext();
		// 放入数据
		User user = new User();
		user.setId(100);
		user.setName("Jack");
		// 【往非根元素放入数据, 取值的时候表达式要用"#"】
		context.put("user", user);
		// 获取数据(map)
		// 先构建一个Ognl表达式, 再解析表达式
		Object ognl = Ognl.parseExpression("#user.name");
		Object value = Ognl.getValue(ognl, context, context.getRoot());
		System.out.println(value);
	}
	
	/**
	 * 2. Ognl表达式语言语言取值,取根元素的值,不用带#号
	 * @throws Exception
	 */
	@Test
	public void testOgn2() throws Exception {
		// 创建一个Ognl上下文对象
		OgnlContext context = new OgnlContext();
		// 放入数据
		User user = new User();
		user.setId(100);
		user.setName("Jack");
		// 【往根元素放入数据】
		context.setRoot(user);
		// 获取数据(map)
		// 先构建一个Ognl表达式, 再解析表达式
		Object ognl = Ognl.parseExpression("name");
		Object value = Ognl.getValue(ognl, context, context.getRoot());
		System.out.println(value);
	}
	
	/**
	 * 3.Ognl对静态方法调用的支持
	 * @throws Exception
	 */
	@Test
	public void testOgn3() throws Exception {
		// 创建一个Ognl上下文对象
		OgnlContext context = new OgnlContext();
		// Ognl表单式语言,调用类的静态方法
		//Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
		// 由于Math类在开发中比较常用,所以也可以这样写
		Object ognl = Ognl.parseExpression("@@floor(10.9)");
		Object value = Ognl.getValue(ognl, context, context.getRoot());
		System.out.println(value);
	}
}

7、ValueStack对象:即值栈对象。
① 是整个struts数据存储的核心,或者叫中转站。
② 过程:用户每次访问struts的action,都会创建一个Action对象、值栈对象、ActionContext对象,然后把Action对象放入值栈中,最后再把值栈对象放入request中,传入jsp页面。
③ (key: struts.valueStack);开发者只需要通过ActionContext对象就可以访问struts的其他的关键对象(ActionContext是给开发者用的,便于学习与使用)

/**
 * struts的数据流转
 */
public class OgnlDemo extends ActionSupport{
	// 根元素值
    private User user = new User(100,"Jacks");
    public User getUser() {
		return user;
	}
    public void setUser(User user) {
		this.user = user;
	}
	
	@Override
	public String execute() throws Exception {
		ActionContext ac = ActionContext.getContext();
		// 映射数据
		ac.getContextMap().put("request_data", "request_data");
		// 数据存储request
		// Map<String,Object> map = (Map<String, Object>) ac.get("request");
		// map.put("request_data", "request_data");
		// map.put("cn", "China");
		ac.getSession().put("Session_data", "Session_data");
		ac.getApplication().put("Application_data", "Application_data");
		
		// 二、值栈对象的存储数据的原理
		ValueStack vs = ac.getValueStack();
		/***************操作根元素的几种方法*****************/
		// 设置数据: 入栈
		//vs.push(new User(1002,"Tom"));	// 栈顶
		//vs.pop();		// 移除栈顶元素
		// 如何存储?  map结构存储  
		//vs.set("user1", new User(1,"Jacky1"));
		//vs.set("user2", new User(2,"Jacky2"));
		return super.execute();
	}
	// 一、获取值栈对象的2种方式
	private void getVs() {
		// 获取值栈对象,方式1:
		HttpServletRequest request = ServletActionContext.getRequest();
		ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");
		// 获取值栈对象,方式2: 
		ActionContext ac = ActionContext.getContext();
		ValueStack vs2 = ac.getValueStack();
		
		System.out.println(vs1 == vs2);//true
	}	
}

Struts标签取值,就使用了Ognl表达式语言。

<%@ 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 'index.jsp' starting page</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
  </head>
  
  <body>
  	<!-- 页面: 必须要拿到ValueStack -->
     <br/>1. 取根元素的值<br/>
     <s:property value="user.id"/> 
     <s:property value="user.name"/> 
     <s:property value="user.address"/> 
     <s:property value="user.address.city"/> 
     <s:property value="user.address.province"/> 
     <br/>2. 取非根元素的值<br/>
     <s:property value="#request.cn"/>
     <s:property value="#session.Session_data"/>
     <s:property value="#application.Application_data"/><br/>
     <!-- 自动找request/session/application,找到后立刻返回 -->
     <s:property value="#request_data"/>
     <s:property value="#attr.Session_data"/>
     <s:property value="#attr.Application_data"/>  <br/>
     <!-- 获取请求的参数数据 -->
     <s:property value="#parameters.userName"/>
     <!-- struts的调试标签:可以观测值栈数据 -->
     <s:debug></s:debug>
  </body>
</html>

猜你喜欢

转载自blog.csdn.net/Mr_GaoYang/article/details/82743911