Struts2 学习笔记

 
Struts2 五大核心部分:
操作(Actions)
拦截器(Interceptors)
值栈(Value Stack)/OGNL
结果(Result)/结果类型  
视图技术		--未学习

Struts2 主要功能:struts.xml 中  传值  跳转 
	struts2最重要的是拦截器,个人认为strut2是一个表述层与业务逻辑层进行数据交互的一个框架

流程: 当通过web程序点击一个超链接或表单时,由控制器(Dispatcher Filter Interceptors)收集输入,发送一个Action 的java类,Action执行后,
Result会选择一个资源给与响应。这个资源通常是一个jsp 或者其他资源类,

----Action 学习-----------------------------------------------------------------------------------------
Servlet和action区别
	Servlet默认第一次访问的时候创建,创建一次,单实例对象。
	action每次访问的时候创建,创建多次,多实例对象。
Action 实现方式分为两大类:
	属性驱动: 
		使用属性作为贯穿MVC的信息携带者,依附于Action实例,Action实例封装请求参数和处理结果
		实现方式
				1 普通pojo 类
					 jsp:
						<form action="test/login" method="post">
							用户:<input type="text" name="username"><br>
							密码:<input type="password" name="password"><br>
							<input type="submit" value="登陆"><br>
						</form>
					struts.xml:
						<struts>
							// package name 逻辑上的包名,namespace 命名空间 extends 继承某个配置文件
							<package name="lee" extends="struts-default" namespace="/test">  // 这里的test 指定url的资源层级
							// 根据Struts定义的自动装配策略
							<constant name="struts.objectFactory.spring.autoWire.alwaysRespect" value="true" />
							<action name="login" class="action.LoginAction" method="execute">  // 指定执行的action方法名称
								//result name:Action 类的映射名 class:action类的完整路径  method: 默认 execute 需要自定义
								<result name="success" type="dispatcher">/welcome.jsp</result>
								<result name="error" type="dispatcher">/fail.jsp</result>  // 物理路径(绝对路径),即指在项目中的实际位置
							</action>
							</package>
						</struts>
					action 类:
						//普通的execute方法
						public class LoginAction  {
							public String execute() throws Exception {
								if("test".equals(getUsername())&&"123".equals(getPassword())){
									return "success";  // 这里对应的结果集 result name
								}else{return "error";}
							}
						}
					
				2 实现Action接口
					action类:
						public class LoginAction1 implements Action {
							//execute方法,和方式一比较“success”变为SUCCESS ERROR变为ERROR
							public String execute() throws Exception {
								if("test".equals(getUsername())&&"123".equals(getPassword())){
									return SUCCESS;
								}else{return ERROR;}
							}
						}
				3 继承ActionSupport
					action类:    //struts2的拦截器机制  getter   setter 方法负责解析用户请求参数  并且将请求参数值赋给action对应的属性
						public class LoginAction2 extends ActionSupport {
							//execute方法和方式二比较没变
							public String execute() throws Exception {
								if("test".equals(getUsername())&&"123".equals(getPassword())){
									return SUCCESS;
								}else{return ERROR;}
							}
						}
				
	模型驱动: 使用单独的JavaBean 实例来贯穿MVC流程,JavaBean实例封装请求参数和处理结果
			实现方式: 1 创建 User 类 implements Serializable
					   2 创建Action
							public class LoginAction3 implements Action,ModelDriven<User> {
								    private User user=new User(); //定义用于封装请求参数和处理结果的Model
									public String execute() throws Exception {			//execute方法和方式二比较没变
										if("test".equals(user.getUsername())&&"123".equals(user.getPassword())){
											return SUCCESS;
										}else{return ERROR;}
									}
									@Override				//重写getModel方法
									public User getModel() {
										return user;
									}
							}
		
	
	代码讲解: 前期导包
		1:配置 web.xml   添加 filter - name=随便写  class=org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
								filter-mapping  name=随便写的名称  <url-pattern>/*</url-pattern>
		2:配置 struts.xml 位置在WEB-INF classses 下
				<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd">
				<struts></struts>	

		     如果有很多action,需要创建action 的 xml,然后在 struts.xml 中引入 <include file="struts-user.xml"></include> 

		自动装配原理:【org.apache.struts2.StrutsConstants类】  <constant name="struts.objectFactory.spring.autoWire.alwaysRespect" value="true" />
			首先根据在Struts.xml中定义Action时指定的class属性值获取Action实例即appContext.getBean(beanName)
			如果获取到,则直接返回。此时所使用的自动装配策略是applicationContext.xml中设置的装配策略。	
				applicationContext.xml中beans的默认自动装配策略是no,所以如果没有设置<beansdefault-autowire="autodetect">或者bean的autowire="byName",则Action中的属性比如personManager不会进行自动装配。
			如果获取不到,则调用buildBean(beanClazz, extraContext)。
				 如果struts.objectFactory.spring.autoWire.alwaysRespect为true,此时会根据Struts定义的自动装配策略(struts.objectFactory.spring.autoWire)进行自动装配。
				 如果struts.objectFactory.spring.autoWire.alwaysRespect为false,则按constructor方式进行自动装配。
				 
	一个action 中包含了多个请求处理方式:
		
		方法1: DMI(动态方法调用) Dynamic Method Invocation
		
			表单元素的action不直接等于某个Action的名字,而是以感叹号后加方法名来指定对应的动作名:、
				<!-- 动态方法调用HTML标签与Struts2标签 -->
				<form action="computeAction!add.action" name="from" >
				<s:form action="computeAction!add.action" name="form" theme="simple" >
				写法就是 action 加上 ! 加上action内的指定方法名 最后加上 .action
				
			注意:要使用动态方法调用,必须设置Struts2允许动态方法调用  <constant name="struts.enable.DynamicMethodInvocation" value="true" />
			例子:
				jsp:	<s:form name="form" theme="simple">
							num1:<s:textfield name="num1" />
							num2:<s:textfiled name="num2" />
							<s:submit type="button" value="加" οnclick="computeMethod('add')" />
							<s:sibmit type="button" vlaue="减" οnclick="computeMethod('substract')" />
						<s:form>
						
						<script type="text/javascript">
							function computeMethod(op){
								document.form.action = "computeAction!"+op; //动态选择处理请求的方法
								document.form.submit(); //提交
							}
						</script>
				struts.xml:
					<constant name="struts.enable.DynamicMethodInvocation" value="true" />
					<package name="struts2" extends="struts-default">
						<action name="computeAction" class="com.struts.ComputeAction">
							<result name="fruitPage" >/fruit.jsp</result>   // 这里result name 属性就是action实例方法返回的字符串
						</action>
				fruit.jsp响应结果的页面
					<body>
						<!-- 结果页面 -->
						计算结果:<s:property value="fruit" /> // fruit 是 action实现类中定义的结果集,注意必须要有get方法  这里就不写了。
					</body>
		
		方法2 : action 添加 method  会造成一个请求一个action 这里就不写了
		
		方法3: 使用通配符映射方式
				jsp:		
							 <s:form name="form" theme="simple" >
								num1:<s:textfield name="num1" />
								num2:<s:textfield name="num2" />
								<s:submit type="button" value="加" οnclick="computeMethod('addAction')" />
								<s:submit type="button" value="减" οnclick="computeMethod('subtractAction')" />
							</s:form>
							<script type="text/javascript">
								function computeMethod(op){
									document.form.action=op;//相比mothod属性改动只有这里  这里把参数作为action对象
									document.form.submit();//提交}
							</script>
				struts.xml:
							<package name="struts2" extends="struts-default">
								<action name="*Action" class="com.struts.ComputeAction" method="{1}" >
									<result name="fruitPage" >/fruit.jsp</result>
									<!-- <result name="fruitPage" >/{1}.jsp</result>表达式也可以写在这里 -->
								</action>
								
							</package>

拦截器----------------------------------------------------------------------------------------------
过滤器和拦截器的区别
	过滤器:在启动时创建。过滤器理论上可以过滤任何内容,比如 html、jsp、servlet、图片路径。
	拦截器:拦截器可以拦截的内容,只会拦截action类型请求。所以标准写法要在请求后面加上".action"这个后缀。

拦截器是struts2 特有的,struts2 封装了很多功能,封装的功能都在拦截器里
默认拦截器位置: struts2-core-2.xxxx.jar—->struts-default.xml,在这里面配置了很多的拦截器,但是只执行默认配置的那些拦截器。
拦截器的执行时间:
	action代理对象创建之后,action目标处理逻辑方法执行之前。只要配置了拦截器,不管是否使用都会被执行。
拦截器依赖的两个技术:动态代理     过滤链
拦截器的两个原理:
	AOP思想:面向切片,在不修改代码片的前提下使用配置文件来达到切入代码的功能
	责任链模式:  和过滤链类似,一个请求有多个过滤器过滤,每个过滤器执行后才到下一个过滤器。
		action目标逻辑方法的执行是通过动态代理方式执行,和直接创建action对象执行没有区别。
	原理如何应用到拦截器内:
		在action方法执行前执行默认拦截器,执行过程使用AOP思想,action没有直接调用拦截器的方法,只能走配置文件。
		执行很多拦截器使用的是责任链模式。
		三大组件执行顺序:listener --> filter --> servlet
		
拦截器的构造:
	以模型驱动ModelDriven 为例:
		public class ModelDrivenInterceptor extends AbstractInterceptor{}
		AbstractInterceptor 有三个方法: 1 init() 初始化  2  destory 销毁  3 String intercept(ActionInvocation invocation) 拦截器逻辑操作
	创建拦截器方法:
		1: extends AbstractIntercepter  需要些反射代码,比较麻烦 不推荐
		2: extends MethodFilterInterceptor  能够让action某个方法不进行拦截
		
			例: 实现action超链接只有登录状态才能进入  这里需要对所有的action都进行拦截才能判断是否登录
			
				jsp:<form action="selfdefinedlogin" method="post">  首先要有个登录功能页面
							<input type="text" name="name" placeholder="用户名"><br>
							<input type="text" name="password" placeholder="密码"><br>
							<input type="submit" value="登录">
					</form>
				action: 服务端有个登录action
					 private User us;
					 public String execute(){
						if(us.getName()==null||us.getPassword()==null)return "error";
						if(!us.getName().equals("FireLang")||!us.getPassword().equals("lang")){
							return "error";
						}
						ActionContext.getContext().getSession().put("FireLang", us.getName()); // 将用户写入session
						return "success";
					 }
					  @Override			// 别忘了这里的模型驱动
					public User getModel() {
						us=new User();
						return us;
					}
				添加登录拦截器,判断session是否有该用户
				
				创建拦截器:public class DefinedInterceptor extends MethodFilterInterceptor{
								@Override
								protected String doIntercept(ActionInvocation invocation) throws Exception {
									String name=(String)ServletActionContext.getRequest().getSession().getAttribute("FireLang");
									if(name==null){return "error";}
									return invocation.invoke();// 类似filter 放行 进行下一个拦截器或者action 但是必须有return 返回action结果
								}
							}
				注册拦截器: struts.xml
					<!-- 声明拦截器,注意这里还没有使用拦截器 -->
					<interceptors>
						<interceptor name="definedlogin" class="cn.domarvel.selfdefined.DefinedInterceptor"/>
					</interceptors>
					
					在action标签内使用拦截器: <interceptor-ref name="definedlogin"/>
											  <interceptor-ref name="defaultStack"/> // 为了默认拦截器也能使用 如不用可以不添加
					注意,有个问题,我们在action内配置的拦截器,默认对所有方法都拦截,包括登录方法,这里的拦截器如果使用AbstractInterceptor
					就要写反射来实现不拦截所有,而 MethodFilterInterceptor 可以通过配置实现不拦截所有。
						还是action标签内  <interceptor-ref name="definedlogin">
								<!-- param的name属性值不要写错了,不然它本身也不会报错,也会不起作用,这样很难找到错误的 -->
								<!-- param里面的值为方法名称,多个方法名称用","逗号隔开 -->
								<!-- 这样就能够让execute方法不会被当前配置的拦截器拦截了,但是因为不是配置的默认拦截器,所以默认拦截器还是会执行的 -->
												<param name="excludeMethods">execute</param>  // 这里是不拦截的方法
											</interceptor-ref>
											
				整体拦截器配置:
						<!-- 拦截器配置的整体代码  注意 这里只对当前action有效,对其他action无效 -->  
						<package name="px" extends="struts-default" namespace="">
								<interceptors>
									<interceptor name="definedlogin" class="cn.domarvel.selfdefined.DefinedInterceptor"/>
								</interceptors>

								<action name="selfdefinedlogin" class="cn.domarvel.selfdefined.loginAction">
									<interceptor-ref name="definedlogin">
										<param name="excludeMethods">execute</param>
									</interceptor-ref>
									<interceptor-ref name="defaultStack"/>
									<result name="error">/WEB-INF/content/selfdefined/failed.jsp</result>
									<result name="success">/WEB-INF/content/selfdefined/successx.jsp</result>
								</action>
						</package>


Result 结果集----------------------------------------------------------------------------------------------
Result组件是Struts2中用于输出的组件,实际上就是Java代码,Struts2中预制了10中类型的Result
	注意:若JSP页面中表单是用普通<form>编写的,发生错误而返回该页面时,则原数据将消失
		  若JSP页面中表单是用<s:form/>编写的,发生错误而返回该页面时,则原数据仍存在
	 <!-- 默认视图主题 -->
	 <constant name="struts.ui.theme" value="simple"></constant>  
	  <!-- name属性:包名,用于被别的包调用或继承 
        extends: 继承哪个包,会继承该包下配置信息和拦截器等等
        namespace:选填,url连接必须加入/new/action.xxx
     -->
	 <package name="user" namespace="/ss" extends="struts-default">  

	1 配置 result 映射
		指定实际资源的位置 绝对路径 / 开头 相对于当前的Web应用程序的上下文路径;
						   相对路径 不以/ 开头,相对于当前执行的action的路径,也就是namespace指定的路径。
			如:	 <action name="login" class="com.ibm.LoginAction">  如果这里class没有指定 默认会跳转到
							<result>success.jsp</result>
							<result name="error" type="dispatcher">/error.jsp</result>
					</action>
					
		param 固定参数:<param name="actionName">****</param> 
						<param name="location">
						<param name="parse">
						<param name="root"> 
						<param name="includeProperties"> 
							
						 
		result 参数: name 要跳转的目标资源 可以是action  url
					type:要跳转的结果类型,具体如下面 也可以直接写jsp名称,默认dispatcher
		action参数:name action名称
					namespace  资源位置定义
					
	2 result 结果类型  相当于springmvc 中的 requestmapping(value="")  用于处理请求并转到对应的动作执行
		注意: 传递中文,记住永远不要在浏览器的地址栏中传递中文。在传递中文前先进行编码
			action中:	 username=URLEncoder.encode("郭蕾","utf-8");//先进行编码
			struts.xml 中 <action name="redirect" class="action.User">
							<result type="redirect" name="redirect">
							/redirect.jsp?username=${username}//如果要传递两个参数,中间用&代替&</result>
						 </action>
			jsp 中:<body>
					   重定向
					   <%String s=request.getParameter("username");
						s=new String(s.getBytes("iso8859-1"),"utf-8"); // 这里进行编码转换
						s=URLDecoder.decode(s,"utf-8");
						out.println(s);
						%>
					 </body>
					


		几种类型:
		chain: 用来处理action链,	com.opensymphony.xwork2.ActionChainResult
			从一个action 转发到另一个action
				四个属性:
					actionName 
					namespace 
					method 
					skipActions 
		dispatcher(默认): 用来转向页面,通常处理 JSP  org.apache.struts2.dispatcher.ServletDispatcherResult
				实现类的两个属性 location和parse 通过 param 设置,如
					<!-- 预算管理办导航 -->
					<action name="budgeteeringIndex3">
						<result name="success" type="dispatcher">
							<param name="location">budgeteering_3.jsp?id=${id}</param> //location参数用于指定action执行完毕后要转向的目标资源
							<param name="parse">true</param>  true 解析 location 参数中的ongl 表达式,false 不解析 默认true
						</result>
					</action>
					
		redirect: 重定向到一个url   				  org.apache.struts2.dispatcher.ServletRedirectResult
			后台使用HttpServletReseponse.sendRedirect() 将请求重定向到指定的url,在这个场景中,用户和服务端交互浏览器需要两次请求,
			并且第一次请求的数据在第二次请求中是不可用的,意味着目标资源中无法访问action实例,如果要访问,两种方法:
				1:将数据保存到session
				2:通过请求参数传递数据				这里涉及到一个问题 参数如果是中文怎么办?
					如:<action name="gatherReportInfo" class="...">
							<result name="showReportResult" type=""redirect">
								<param name="location">generateReport.jsp</param>
								<param name="namespace">/genReport</param>  定义资源位置
								<param name="reportType">pie</param>  参数1
								<param name="width">100</param> 	  参数2
								<param name="height">100</param> 	  参数3
						url = /genReport/generateReport.jsp?reportType=pie&width=100&height=100  

			
		redirectAction: 重定向到一个action 		  org.apache.struts2.dispatcher.ServletActionRedirectResult
			主要防止用户重复提交表单
				<action name="login" class="...">
					<result type="redirectAction">
						<param name="actionName">dashboard</param>
						<param name="namespance">/secure</param>			//重定向到不同命名空间下的 action
					</result>
				</action>
				重定向到同一个命名空间下
				<action name="dashboard" class="...">
					<result>dashboard.jsp</result>   			//不出错跳转到这里 默认是 dispatcher
					<result name="error" type="redirectAction"></result> //如果出错的话跳转到这里
				<action name="error" class="..."> 	// 这里是出错后跳转
					<result>error.jsp</result>
				</action>
						
			
		plainText: 显示源文件内容,如文件源码		  org.apache.struts2.dispatcher.PlainTextResult
		freemarker:处理 FreeMarker 模板
		httpheader:控制特殊 http 行为的结果类型
			  httpheader结果类型很少使用到,它实际上是返回一个HTTP响应的头信息
			  
		stream:向浏览器发送 InputSream 对象,通常用来处理文件下载,还可用于返回 AJAX 数据。  org.apache.struts2.dispatcher.StreamResult
				验证码例子:
					<!-- 生成验证码的Action -->  
					<action name="createImage"  
						class="com.netctoss.action.CreateImageAction">  
						<result name="success" type="stream">  
							<param name="inputName">  
								imageStream  
							</param>  
						</result>  
					</action>  
					
					action实例:extends BaseAction
						private InputStream imageStream;   输出用
						 public String execute() {  
							Map<String,BufferedImage> map =  ImageUtil.createImage();   //生成验证码图片 						
							String imageCode =   map.keySet().iterator().next();  //通过遍历得到唯一生成的验证码  
							session.put("imageCode", imageCode);  //将验证码记录到session,在登录验证时使用  
							BufferedImage image = map.get(imageCode);  //根据验证码,得到图片  
							try {  
								imageStream =  ImageUtil.getInputStream(image);  //将图片转换为输入流,由result作输出 
							} catch (IOException e) {  
								e.printStackTrace();  
								return "error";  
							}  
							return "success"; 
						}
						
					
		velocity:处理 Velocity 模板
		xslt:    处理 XML/XLST 模板
		
		json 虽然这里没有,但是常用页面的异步校验,使用方式为:
			1:导包:struts2-json-plugin-2.1.8.1.jar
			2:struts.xml中将要使用json类型Result的package继承json-default
			3:在struts.xml中配置result
			
			如: 输出单个属性
				<result name="success" type="json" >  
					//注意:name="root"是固定用法;如指定的属性是boolean类型,那么Result会把这个属性做成字符串"true";
					// 如指定的属性是JavaBean,那么Result会把这个属性做成字符串{"code":"12"}
						<param name="root">    
								指定Action的一个属性名  
						<param>  
				</result>  
				
				输出多个属性
					<result name="success" type="json">  
							<param name="includeProperties">  
									属性名1,属性名2,...  //Result会将这一组属性做成一个json输出 如 {"code":"aaa","name":"zs"}
							</param>  
					</result>
				输出所有属性
					<result name="success" type="json">  
                    </result>  
		


值栈-------------------------------------------------------------------------------------------------
ValueStack
private OgnlValueStack iognlvstack_Stack;

	public ValueFinder(ServletRequest areq_R) {
		iognlvstack_Stack = null;
		if (areq_R == null)
			System.out.println((new StringBuilder()).append(getClass().getName())
					.append(".ValueFinder(): areq_R is null").toString());
		else
			iognlvstack_Stack = (OgnlValueStack) areq_R.getAttribute("struts.valueStack");
	}
1.ValueStack有一个实现类叫OgnlValueStack. 
2.每一个action都有一个ValueStack.(一个请求,一个request,一个action,一个valueStack) valueStack生命周期就是request生命周期。 
3.valueStack中存储了当前action对象以及其它常用web对象(request,session,application.parameters) 
4.struts2框架将valueStack以“struts.valueStack”为名存储到request域中。
	Struts2 中valueStack 内部有两部分,Map(OgnlContext) List(root)
	ValueStack中 存在root属性 (CompoundRoot)--ArrayList 
			    context 属性 (OgnlContext )--Map   基本很少操作这个对象
		list集合中存储的是action相关信息    我们想要从list中获取数据,可以不使用#号.(它就是ognl的root) 
			下面来讲讲root 存储内容:
				root 是一个栈的存储结构,默认存储内容:
						action 对象引用		root栈顶存储 向值栈里放数据主要放在root里
						DefaultTextProvider
	    map集合中存储的是相关映射信息,包含 
				paramters 传递相关的参数 
				request --RequestMap 底层是 HttpServletRequest
				session —>HttpSession对象引用 
				application —>ServletContext对象引用
				attr r—>使用attr操作,能够获取域对象里面的值,获取域范围最小里面的值
				如果从map中获取数据,需要使用#.	 通过struts2的标签<s:debug></s:debug>
		
对于 valueStack 获取有两种方式:
	1: 通过 request 获取 
		ValueStack vs=(ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
	2: 通过 ActionContext 获取
		ValueStack vs=ActionContext.getContext().getValueStack();
		
向值栈保存数据的两个方法:(主要针对root)
	1:push(Object obj)——->底层就是 root.add(0,obj) 将数据存储到栈顶。   调用push之后,就会在root栈顶放入一个String类型的对象
		如: 同样放到 execute方法内
			ActionContext.getContext().getValueStack().push(us);
			ActionContext.getContext().getValueStack().push("FireLang");
	2:set(String name,Object obj);—–>底层是将数据封装到HashMap中,在将这个HashMap通过push存储。
		如: 放在execute 方法内部
			ValueStack stack=ActionContext.getContext().getValueStack();
			stack.set("username","FireLang");  // 在用set方法添加值栈数据之后,会在root栈顶多一个HashMap对象
			
			
	3: 在action定义变量,生成变量的get方法  -- 常用	
		如:private String name;  这里必须要有 execute 方法 return "success";
			public String getName(){ 这里可以返回String  也可以返回对象 如返回对象的话使用为 <s:property value="us.name" />  return us;
				return name;  
			}
			获取: <s:property value="name"/>  这里的name是ognl表达式。表示获取action中的name字段值,必须要写get方法
		在用第三种方法之后,struts2并不会在值栈root的栈顶放入新的对象,它的存储路径还是存储在action里面,所以这就起到了资源的合理应用,
		当想要获取name属性的时候,就会在值栈里面调用action的getName方法。这也就是为什么会在值栈里面存储action的原因了
		
		如果这里要获取list 类型的值: 这里使用的是Ongl 也可以使用el表达式来获取${object.name }
		<s:iterator value="object"> //object 有name  password 属性 这里的object 是action get 方法返回值的名称
			<s:property value="name"/>
			<s:property value="password"/>
			<br><hr><br>
		</s:iterator>

		如果使用el表达式的话,el取值能够获取到action里面的值,具体原理就是,它重写的request,进行了request域的增强,里面进行了以下操作:
			el取值时,如果request域里面能够找到目标值,那么就把值返回到页面。如果在request域里面不能够取到目标值,那么就通过值栈获取。
			el在获取Action里面的值时,action里面的字段也必须提供get方法。否则无法获取到值。
			
	工作原理:https://blog.csdn.net/pwlazy/article/details/2318494
	
	
	
	
	
过滤器 ------------------------------此功能并非struts2特有---------------------------------------------------
Servlet Filter讲解:
	请求预处理(改变request)	
	响应预处理(修改response)
	filter其实是客户端与servlet中间的一个传递者,并且它可以对要传递 的东西进行修改。注意  filter只拦截请求响应,不会产生响应,那是servlet干的事。
	
	适用场合:   实现URL级别的权限访问控制,过滤敏感词汇,压缩响应信息等。

	拦截步骤: 1 客户端请求,在 HttpServletRequest 到达Servlet 之前进行拦截,
			   2  检查和修改 HttpServletRequest
			   3 过滤器中调用doFilter 方法,对请求放行。请求到servlet后,对请求处理并产生HttpServletResponse 发送给客户端。
			   4 服务端响应 HttpServletResponse 在到达客户端之前,被拦截。
			   5 检查和修改 HttpServletRespinse
			   6 HttpServletResponse 到达客户端
			   
	实现接口: Filter 接口
		三个重要方法: init():初始化参数,创建Filter时自动调用
							这里写入web.xml 的 <init-param>在这里初始化
							init(FilterConfig filterConfig)  init 的时候默认将FilterConfig 传入
							如 		redirectURL = filterConfig.getInitParameter("redirectURL"); redirectURL param-name名称
					   doFilter(ServletRequest,ServletResponse): 拦截后的处理 
							这里可以实例化 HttpServletRequest 和 HttpServletReseponse
								分别对这俩对象进行操作 如
									httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
									最后 filterChain.doFilter(httpServletRequest, httpServletResponse);通过过滤交给servlet/action
							如果有异常直接return 
							否则 FilterChain filterChain.doFilter(servletRequest, servletResponse);
					   destory(): 销毁 filter时调用
	生命周期:
		由web服务器决定,服务器启动,创建Filter 对象,调用 init 方法,filter 只会创建一次,
		拦截到请求,调用doFilter 方法,可以执行多次。
		服务器关闭,销毁Filter 对象。
		
	Filter 接口对象 -- FilterConfig   在Filter 的实现类中的 init()方法内以参数形式传入
		用户配置Filter 时,可以使用 <init-param>初始化参数,web容器初始化init,会把封装了filter 初始化参数的 FilterConfig对象传递进来,
		开发人员只需要操作FilterConfig 对象的方法可以获取以下信息:
			1:String getFilterName()  获取filter名称
			2: String getInitParameter(String name) 根据一个参数名获取参数值,不存在返回null
			3: Enumeration getInitParameterNames() 获取所有初始化参数的名称枚举集合
			4: public ServletContext getServletContext() 获取servlet上下文的引用
			
	过滤器链--FilterChain
		一组过滤器对某些web 资源进行过滤,称之为过滤器链 执行顺序和 filter-mapping 有关
		首先创建filter	<filter>
							<filter-name>自定义</>
							<filter-class>类位置</>
							<init-param><param-name></><param-value></></>
							<init-param><param-name></><param-value></></>
						</filter>
						<filter-mapping>   这里开始过滤 对所有的 action请求进行过滤
							<filter-name>menuAuthCheckFilter</filter-name>
							<url-pattern>*.action</url-pattern>
						</filter-mapping>
						<filter-mapping>  这里开始过滤 对所有的jsp 请求进行过滤
							<filter-name>menuAuthCheckFilter</filter-name>
							<url-pattern>*.jsp</url-pattern>
						</filter-mapping>
		执行顺序: 首先执行第一个filter,doFilter() 前是request  后是response
				执行完第一个按照web.xml 顺序执行第二个,最后交给action,返回的时候是先执行最后一个filter的response 最后才是第一个。栈 先进后出顺序
	使用filter 的几个例子:
	
		1	关于禁用动态缓存: 为啥子要禁用动态缓存??
			// 在response的头部设置Cache-Control、Pragma和Expires即可取消缓存
					HttpServletResponse resp = (HttpServletResponse)response;
					resp.setHeader("Cache-Control", "no-cache");
					resp.setHeader("Pragma", "no-cache");
					resp.setDateHeader("Expires", -1);
					
		2 分IP统计网站的访问次数过滤器
			需要servlet上下文,写入到上下文中去。
			init(FilterConfig)
				ServletContext context = FilterConfig.getServletContext();
				Map<String,Integer> ipCount = new HashMap<String,Integer>();
				application.setAttribute("ipCount",ipCount);
				
			doFilter(ServletRequest request, ServletResponse response,FilterChain chain){
				 String ip = request.getRemoteAddr();//先获取ip
				 Integer count = ipCount.get(ip); 
				 if(count != null){
					 //Map中存在该ip
					 count = count + 1;
				 }else{
					 count = 1;
				 }
				 ipCount.put(ip, count);
				 application.setAttribute("ipCount",ipCount);  // 这里放到上下文中
				 chain.doFilter(request, response);
			}
			前端可以使用js 的标签库处理  <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
			 <c:forEach items="${ipCount}" var="m">
				<tr>
					<td>${m.key}</td>
					<td>${m.value}</td>
				</tr>
			 </c:forEach>
			 
		3 自动登录
			逻辑流程: 先判断session中是否存在,存在则放行,不存在则判断cookie中是否存在用户名密码,存在则到数据库中查询是否正确,正确则存入session并放行,不正确则放行。
			filter:
				HttpServletRequest req = (HttpServletRequest)request;
				HttpSession session = req.getSession();
				UserInfo user = (UserInfo)session.getAttribute("user");
				if(user != null){
					chain.doFilter(req, response);
				}else{
					//session中不存在用户
					Cookie[] cookies = req.getCookies();
					Cookie cookie = CookieUtil.findCookie(cookies, "autoLogin");
					if(cookie!=null){  //在cookie中找到该用户
						UserInfoBiz ubiz = new UserInfoBizImpl();
						String name = cookie.getValue().split("#oracle#")[0]; // 在cookie 中找到这个用户
						String pwd = cookie.getValue().split("#oracle#")[1];
						String msg = ubiz.login(name, pwd);
						if("登陆成功!".equals(msg)){
							user = ubiz.getByName(name);
							session.setAttribute("user", user);
							chain.doFilter(req, response);
						}else{
							chain.doFilter(req, response);
						}
			servlet 实现:
				 HttpSession session = request.getSession();String name = request.getParameter("myname");String pwd = request.getParameter("pwd");
				 String autoLogin = request.getParameter("autoLogin");
				 UserInfoBiz ubiz = new UserInfoBizImpl();
				 String msg = ubiz.login(name, pwd); // 检查是否有权限
				 if("登陆成功!".equals(msg)){
					UserInfo user = ubiz.getByName(name);
					session.setAttribute("user", user);
					if("true".equals(autoLogin)){
						Cookie cookie = new Cookie("autoLogin",user.getUserName()+"#oracle#"+user.getPassword()); //利用cookie记住用户名和密码
						cookie.setMaxAge(60*60*24); //设置有效时间
						response.addCookie(cookie); //将cookie回写到浏览器
					} response.sendRedirect("success.jsp");
					
			cookie 实现:
				public static Cookie findCookie(Cookie[] cookies,String name){
					if(cookies==null){
						return null;
					}else{
						for(Cookie cookie:cookies){
							if(cookie.getName().equals(name)){
								return cookie;
							}
						}
						return null;
					}
				}
		
								
		String 拦截器 和 Struts2 过滤器filter区别:
			两者的本质区别:拦截器是基于java的反射机制的,而过滤器是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,他都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。
						
					   
	
	session-------------------------------------------------------------------------------------------------
	Session 学习:
		actipon 获取session  两种方式:
		方法1: extends ActionSupport 
				execute(){
					ActionContext actionContext = ActionContext.getContext();
					Map session = actionContext.getSession();
					session.put("USER_NAME", "Test User");return SUCCESS;
				}
		方法2:implements SessionAware 
				private Map session;
				实现 public void setSession(Map session) {
						this.session = session;
					}    
					
	struts2的session,也是web应用的session,它是httpsession,存在于服务器上,对应每个浏览器进程,也就是说每个客户端浏览器进程对应服务器上的一个session,它采用key-value的结构。同时这个session还有一个生存周期。由于session会消耗服务器内存,因此尽量不要将大数据放到session中。

	hibernate中session,是从获得数据库连接到释放(不一定是关闭)数据库连接,在一个sesion的范围内,对数据库的操作是一个事物。在没有处理分布式事物时,存在于当前线程内
	
	
ActionContext和ServletActionContext的区别 -----------------------------------------------------------------------------------

ActionContext主要负责值的操作;ServletActionContext主要负责获取Servlet对象。
优先使用ActionContext
只有ActionContext不能满足功能要求的时候,才使用ServletActionContext,要尽量让Action与Web无关,这对于Action的测试和复用都是极其有好处的。

ActionContext 是action 执行的上下文,里边存放着action执行时所需的对象,我们成为 广义值栈。类似 ValueStack
		可获取的信息 request,session,ServletContext等

		Struts2 每次执行action 都会创建新的 ActionContext,所以是线程安全的。看源码为:
				public class ActionContext implements Serializable {  
					static ThreadLocal actionContext = new ThreadLocal(); // 线程局部变量,为每个使用该变量的线程创建副本,每一个线程可独立改变副本。
					……  	// 存放在ActionContext中的值都放在 ThreadLocal 属性内,只对当前请求线程可见。
				}  
		访问的对向是map类型,为了action 和web解耦,不直接和底层httpsession 交互,所以struts2 封装 httpSession 为一个map 对象。
		因为是解耦的,可以直接在java中访问action的execute 方法,但是因为 ActionContext 包装的都是web数据,仅在java api内无法获取直接使用ActionContext
		
		struts2 提供了另一种访问ActionContext 对象方式: 使用 SessionAware 接口
				该接口通过 Ioc/DI 来为Action 注入 Session Map,是通过servletConfig 拦截器实现的。拦截器在 defaultStack中。
				如:	public class OgnlAction extends ActionSupport implements SessionAware{  	IOC方式
							private Map<String, Object> session;  
							public void setSession(Map<String, Object> session) {  
								this.session = session;  }  // 注意 这里必须有setSession 方法 为 Ioc 提供注入
							public String execute(){  
								session.put("sessionTestKey", "测试SessionAware");  
								return this.SUCCESS;  }  
						}  
				jsp 中获取 Map 内的值:
					<%@ taglib prefix="s" uri="/struts-tags"%>  
					会话中的值:<s:property value="#session['sessionTestKey']"/>  <br>  
					通过Servlet的Api获取会话中的值:<%=session.getAttribute("sessionTestKey") %>  
			为了能够在普通的Java应用中运行并测试Action,推荐大家使用SessionAware的方式来访问HttpSession。

ServletActionContext 存放了Servlet 相关的API信息 如 Cookie Session
	是域对象,一个web应用中只有一个ServletContext,生命周期伴随整个web应用。
	这个类直接继承了 ActionContext 相关父类 信息 如 OgnlValueStack  Action 名字等访问,更重要的是提供了直接访问Servlet 相关对象的功能。
	 可获取的对象有:
		HttpServletRequest:请求对象
		HttpServletResponse:响应对象
		ServletContext:Servlet上下文信息
		PageContext:Http页面上下文
		
		HttpServletRequest request = ServletActionContext.getRequest();  
		HttpServletResponse response = ServletActionContext.getResponse();  
		ServletContext servletContext = ServletActionContext.getServletContext();  
		PageContext pageContext = ServletActionContext.getPageContext();  
		HttpSession session = ServletActionContext.getRequest().getSession();

		通过 implements ServletRequestAware:通过这个接口来获取HttpServletRequest对象
						ServletResponseAware:通过这个接口来获取HttpServletResponse对象
				
			如: action实现    public class OgnlAction extends ActionSupport implements ServletRequestAware{   IOC方式
									private HttpServletRequest request = null;    
									public void setServletRequest(HttpServletRequest request) {  
										this.request = request;  
									}  
									public String execute(){          
										request.setAttribute("request", "Request的属性值");  
										request.getSession().setAttribute("sessionTestKey", "测试SessionAware");  
										return this.SUCCESS;  
									}     
								}  
				jsp 实现:  <%@ taglib prefix="s" uri="/struts-tags"%>  
							Request的属性值:<s:property value="#request['request']"/>br>  
							会话的属性值:<s:property value="#session['sessionTestKey']"/>  
									

struts2中获得request、response和session ---------------------------------------------------------------------------
		
非IOC 方式:
	ActionContext ctx = ActionContext.getContext(); // 静态方法获取
    ctx.put("liuwei", "andy"); //request.setAttribute("liuwei", "andy");
    Map session = ctx.getSession(); //session
    HttpServletRequest request = ctx.get(org.apache.struts2.StrutsStatics.HTTP_REQUEST);
    HttpServletResponse response = ctx.get(org.apache.struts2.StrutsStatics.HTTP_RESPONSE);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值