java框架-struts2


1. struts2访问流程&架构&介绍

  • 自动封装参数、参数校验、结果的处理(转发|重定向)、国际化、显示等待页面、表单的防止重复提交
  • struts2前身:webwork框架(基于filter)与struts1(基于Servlet)两者无关.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 搭建struts2框架

导包:web-content -->web-INF-->lib
asm-3.3.jar
asm-commons-3.3.jar
asm-tree-3.3.jar
commons-fileupload-1.3.1.jar
commons-io-2.2.jar
commons-lang3-3.2.jar
freemarker-2.3.22.jar
javassist-3.11.0.GA.jar
log4j-api-2.2.jar
log4j-core-2.2.jar
ognl-3.0.6.jar
struts2-core-2.3.24.jar
xwork-core-2.3.24.jar

在src下面创建*Action.java
	方法一:创建一个类.不继承任何父类.不实现任何接口.使struts2框架的代码侵入性更低.
	public class DemoAction {
		public String hello(){
			return "success";
		}
	}
	方法二:实现一个接口Action
	import com.opensymphony.xwork2.Action;
	// 里面有execute方法,提供action方法的规范.
	// Action接口预置了一些字符串.可以在返回结果时使用.为了方便
	public class DemoAction implements Action {
		@Override
		public String execute() throws Exception {
			return null;
		}
	}
	方法三:继承ActionSupport
	// 帮我们实现了 Validateable, ValidationAware, TextProvider, LocaleProvider .
	//如果我们需要用到这些接口的实现时,不需要自己来实现了.
	public class Demo5Action  extends ActionSupport{}

创建struts主配置文件在src下创建struts.xml
导入约束window菜单--> preference-->cata 在web App Libraries--struts2-core-2.3.24.jar--struts-2.3.dtd
<?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:将Action配置封装.就是可以在Package中配置很多action.
			name属性: 给包起个名字,起到标识作用.随便起.不能其他包名重复.
			namespace属性:给action的访问路径中定义一个命名空间
			extends属性: 继承一个 指定包
			abstract属性:包是否为抽象的; 标识性属性.标识该包不能独立运行.专门被继承 -->
	<package name="hello" namespace="/hello" extends="struts-default">
			<!-- action元素:配置action类
				name属性: 决定了Action访问资源名.
				class属性: action的完整类名
				method属性: 指定调用Action中的哪个方法来处理请求 -->
		<action name="TestAction" class="com.junye.test.HelloAction" method="fun">
			<!-- result元素:结果配置 
				name属性: 标识结果处理的名称.与action方法的返回值对应.
				type属性: 指定调用哪一个result类来处理结果,默认使用转发.
				标签体:填写页面的相对路径-->
			<result name="success">/hello.jsp</result>
		</action>
	</package>
	<!-- 引入其他struts配置文件 -->
	<include file="cn/junye/b_dynamic/struts.xml"></include>
</struts>

将struts2核心过滤器配置到web.xml,配置在欢迎页前面
	<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>
	
测试:访问http://localhost:8080/mystruts/hello/TestAction

3. strust.xml配置详解

  • struts2常量配置方式(先后也是加载顺序)后加载覆盖
方式1:src/struts.xml(只用这个)
	<constant name="struts.i18n.encoding" value="UTF8"></constant>
方式2:在src下创建struts.properties:
struts.i18n.encoding=UTF8
方式3:在项目的web.xml中
<context-param>
	<param-name>struts.i18n.encoding</param-name>
	<param-value>UTF-8</param-value>
</context-param>
  • struts2常量配置位置App Libraries–struts2-core-2.3.24.jar–org.apache.struts2-default.properties;
<!--常量配置struts.xml-->
<!-- i18n:国际化. 解决post提交乱码 get提交,按以前的方式-->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!-- 指定访问action时的后缀名 
http://localhost:8080/struts2_day01/hello/HelloAction.?默认.action 和 “空”-->
<constant name="struts.action.extension" value="?"></constant>
<!-- 指定struts2是否以开发模式运行1.热加载主配置.(不需要重启即可生效)2.提供更多错误信息输出,方便开发时的调试-->
<constant name="struts.devMode" value="true"></constant>
  • struts2动态方法调用(struts.xml)
通配符方式  使用{1} 取出第一个星号通配的内容
<package name="dynamic" namespace="/dynamic" extends="struts-default" >
	<action name="Demo1Action_*" class="cn.b.Demo1Action" method="{1}" >
		<result name="success" >/{1}.jsp</result>
	</action>
</package>	
访问http://localhost:8080/struts2_day01/dynamic/Demo1Action_find.action跳转到find.jsp
  • struts2中的默认配置
<package name="default" namespace="/default" extends="struts-default" >
	<!--不声明则默认访问,不管整合没整合-->
	<!--<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />-->
	<!-- 声明后找不到包下的action,会使用Demo2Action作为默认action处理请求 -->
	<default-action-ref name="Demo2Action"></default-action-ref>
	<!-- method属性:execute result的name属性:success   result的type属性:dispatcher转发  -->
	<!-- class属性:com.opensymphony.xwork2.ActionSupport -->
	<action name="Demo2Action"   >
		<result  >/hello.jsp</result>
	</action>
</package>
http://localhost:8080/struts2_day01/default/xxxx.action,默认访问Demo2Action
  • 结果跳转方式struts.xml中(result的type属性)用于post/get提交
	转发
	<action name="Demo1Action" class="cn.a_result.Demo1Action" method="execute" >
		<result name="success" type="dispatcher" >/hello.jsp</result>
	</action>

	重定向地址栏发生变化
	<action name="Demo2Action" class="cn.a_result.Demo2Action" method="execute" >
		<result name="success" type="redirect" >/hello.jsp</result>
	</action>

	转发到Action
	<action name="Demo3Action" class="cn.a_result.Demo3Action" method="execute" >
		<result name="success" type="chain">
			<param name="actionName">Demo1Action</param>
			<param name="namespace">/</param>//转发的命名空间
		</result>
	</action>

	重定向到Action
	<action name="Demo4Action" class="cn.a_result.Demo4Action" method="execute" >
		<result  name="success"  type="redirectAction">
			<param name="actionName">Demo1Action</param>
			<param name="namespace">/</param>//转发的命名空间
		</result>
	</action>
  • 全局结果集
<global-result>
	<result name="" type="redirect">/login.jsp</result>
</global-result>
<global-exception-mappings>
	<exception-mapping result="error" exception="java.lang.RuntimeException">
</exception-mapping>
</global-exception-mappings>

4. Action生命周期

  • 1.每次请求到来时,都会创建一个新的Action实例、
  • 2.Action是线程安全的.可以使用成员变量接收参数,servlet线程不安全

5. ActionContext内容

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • attr域以最小的域的map的键为准、request域就是request中的一个map

6. 访问servletAPI方式

通过ActionContext,通过Map原来的方法键值对获得,或者通过封装好的方法获得
//request域=> map (不推荐,ActionContext生命周期和request一样,推荐ActionContext)
//不推荐Map<String, Object> requestScope = (Map<String, Object>) ActionContext.getContext().get("request");
ActionContext.getContext().put("name", "requestTom");//推荐

//session域 => map
Map<String, Object> sessionScope = ActionContext.getContext().getSession();
sessionScope.put("name", "sessionTom");
销毁session:ActionContext.getContext().getSession().invalidate();

//application域=>map
Map<String, Object>applicationScope =ActionContext.getContext().getApplication(); 
操作map put("name","Tom")、remove("name", "Tom")、get("","");

//获得原生response的方法(推荐)
HttpServletResponse response = ServletActionContext.getResponse();
	
通过ServletActionContext(不推荐)获得各种原生域
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
HttpServletResponse response = ServletActionContext.getResponse();
ServletContext servletContext = ServletActionContext.getServletContext();
PageContext pageContext = ServletActionContext.getPageContext();
操作各种域:setAttribute、addAttribute、getAttribute、removeAttribute
通过实现接口方式(用拦截器完成的)
public class Demo7Action extends ActionSupport implements ServletRequestAware {
	private HttpServletRequest request;
	public String execute() throws Exception { 	
		System.out.println("原生request:"+request);
		return SUCCESS;
	}
	@Override
	public void setServletRequest(HttpServletRequest request) {
		this.request = request;
	}	
}

7. jsp获得

page:${pageScope.name};
request: ${requestScope.name}
session:${sessionScope.name}
application:${applicationScope.name}
${name}按顺序取

8. Action接收参数

表单
<form action="${pageContext.request.contextPath}/Demo8Action">
	用户名:<input type="text" name="name" /><br>
	年龄:<input type="text" name="age" /><br>
	生日:<input type="text" name="birthday" /><br>
		<input type="submit" value="提交" />
</form>
单个类型:能获得radio和chekbox的值
属性驱动获得参数:set/get方法
public class Demo8Action extends ActionSupport  {
	//准备与参数键名称相同的属性
	private String name;
	//自动类型转换 只能转换8大基本数据类型以及对应包装类
	private Integer age;
	//支持特定类型字符串转换为Date ,例如 yyyy-MM-dd,一定要有set/get方法
	private Date   birthday;
	public String execute() throws Exception { 
		System.out.println("name参数值:"+name+",age参数值:"+age+",生日:"+birthday);
		return SUCCESS;
	}
}
对象驱动获得参数
public class Demo9Action extends ActionSupport  {
	private User user;//生成set/get方法
	public String execute() throws Exception { 	
		System.out.println(user);
		return SUCCESS;
	}
}
模型驱动获得参数实现接口(只能返回一个对象)
public class Demo10Action extends ActionSupport implements ModelDriven<User> {
	private User user =new User();
	public String execute() throws Exception { 
		System.out.println(user);
		return SUCCESS;
	}
	@Override
	public User getModel() {
		return user;
	}
}
	④radio或checkbox的获取
	只要将属性名字设置成对应的radio或checkbox的值即可获得提交的参数,
	radio是单个值,而checkbox是一行value,空格value的结构,拆分即可
	String[] split = hobby.split(", ");
	for(String s:split) {
		System.err.println(s);
	}
	⑤集合类型参数封装
	list:<input type="text" name="list" /><br>//不指定索引则一个一个塞
	list:<input type="text" name="list[3]" /><br>//指定就放到规定的地方,不指定就null
	private List<String> list;set、get方法
	map:<input type="text" name="map['haha']" /><br>//值封装到键值haha上
	private Map<String,String> map;set/get方法

9. struts、hibernate的javassist-3.18.1-GA.jar包重复,删除版本低的.

10. OGNL表达式

Ognl.png

  • OGNL:对象视图导航语言. ${user.addr.name} 这种写法就叫对象视图导航.
  • OGNL不仅仅可以视图导航.支持比EL表达式(11内置对象)更加丰富的功能.
	使用OGNL准备工作:struts2 的包中已经包含了ognl-3.0.6.jar.不需要导入额外的jar包
	保存
	root和context可以放多个对象或者map,查找时只输入key或者属性名即可。从栈顶一直查到栈低,重复的查不到两个
	User rootUser = new User("tom",18);
	Map<String,User> context = new HashMap<String,User>();
	context.put("user1", new User("jack",18));
	context.put("user2", new User("rose",22));
	OgnlContext oc = new OgnlContext();
	oc.setRoot(rootUser);//将rootUser作为root部分
	oc.setValues(context);//将context这个Map作为Context部分

	基本取值
	//取出root中user对象的name属性
	String name = (String) Ognl.getValue("name", oc, oc.getRoot());
	Integer age = (Integer) Ognl.getValue("age", oc, oc.getRoot());
	//取出context中键为user1对象的name属性#代表context
	String name = (String) Ognl.getValue("#user1.name", oc, oc.getRoot());
	String name2 = (String) Ognl.getValue("#user2.name", oc, oc.getRoot());
	Integer age = (Integer) Ognl.getValue("#user2.age", oc, oc.getRoot());

	赋值
	//将root中的user对象的name属性赋值
	Ognl.getValue("name='jerry'", oc, oc.getRoot());
	String name2 = (String) Ognl.getValue("#user1.name='a',#user1.name", oc, oc.getRoot());

	调用方法(赋值和取值)
	//调用root中user对象的setName方法
	Ognl.getValue("setName('lilei')", oc, oc.getRoot());
	String name = (String) Ognl.getValue("getName()", oc, oc.getRoot());
	String name2 = (String)Ognl.getValue("#user1.setName('lucy'),#user1.getName()", oc, oc.getRoot());

	调用静态方法(static)
	String name = (String) Ognl.getValue("@cn.a_ognl.HahaUtils@echo('hello 强勇!')", oc, oc.getRoot());//@完整类名
	//Double pi = (Double) Ognl.getValue("@java.lang.Math@PI", oc, oc.getRoot());
	Double pi = (Double) Ognl.getValue("@@PI", oc, oc.getRoot())

	创建对象(List,Map)
	Integer size = (Integer) Ognl.getValue("{'tom','jerry','jack','rose'}.size()", oc, oc.getRoot());
	String name = (String) Ognl.getValue("{'tom','jerry','jack','rose'}[0]", oc, oc.getRoot());//tom
	String name2 = (String) Ognl.getValue("{'tom','jerry','jack','rose'}.get(1)", oc, oc.getRoot());//jerry
	Integer size2 = (Integer) Ognl.getValue("#{'name':'tom','age':18}.size()", oc, oc.getRoot());
	String name3  = (String) Ognl.getValue("#{'name':'tom','age':18}['name']", oc, oc.getRoot());
	Integer age  = (Integer) Ognl.getValue("#{'name':'tom','age':18}.get('age')", oc, oc.getRoot());

10.1. OGNL与Struts2的结合原理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

	接口ValueStack实现类OgnlValueStack包括root和context两部分
	public class OgnlValueStack implements ValueStack{
		CompoundRoot root;//栈结构
		transient Map<String,Object> context;//map结构
	}

	//root是栈,是由ArrayList和栈方法模拟的,访问栈中属性的特点.由上到下
	//默认情况下,root放置的是被访问的当前Aciton,请求参数被封装到Action中
	public class CompoundRoot extends ArrayList{
		//栈方法:弹栈
		public Object pop(){
			return remove(0);
		}
		//栈方法:压栈
		public Object push(Object o){
			add(0,o);
		}
	}
	查看值栈中两部分内容
	(使用DEBUG标签)<s:debug></s:debug>

10.2. struts2与ognl结合体现

  • 参数接收

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 获得ValueStack和ActionContext的方法

    • 获得ActionContext数据中心: ActionContext.getContext();
    • 获得值栈:ActionContext.getContext().getValueStack();
  • ValueStack的API(少用)常用来接收表单数据,很少往这root放数据

    • 将数据obj放入值栈ValueStack中的Root:ActionContext.getContext().getValueStack().push(obj);
    • 从值栈ValueStack中的Root将数据obj取出:ActionContext.getContext().getValueStack().pop();
    • 从值栈ValueStack中的Root将查询数据Object findValue = ActionContext.getContext().getValueStack().findValue(“name”);
    • 从值栈ValueStack中的Root将修改数据ActionContext.getContext().getValueStack().setParameter(“name”, “name”);
    • 通过键值对key和value将数据放入值栈ValueStack中的Context:ActionContext.getContext().put(key, value);
    • 通过键名找到值栈ValueStack中的对象Object object = ActionContext.getContext().get(“name”);
    • 可以通过EL表达式${}从值栈中的Context取数据
<action name="Demo4Action" class="cn.a_result.Demo4Action" method="execute" >
	<result  name="success"  type="redirectAction">
		<param name="actionName">Demo1Action</param>
		<param name="namespace">/</param>//转发的命名空间
		<param name="name">{{name}}</param>//转发的命名空间
	</result>
</action>
语法:${ognl表达式},将数据传递到结果那边,不过一般都是在域中传递,不常用
可以通过EL表达式${}从值栈中的Context取数据

扩展:request对象的getAttribute方法
同时也是ognl表达式获得参数的方法(查找顺序)
request.getAttribute()
原生request域
查找valueStack的Root部分(栈)
查找valueStack的context部分(ActionContext)

11. 自定义拦截器

//拦截器生命周期:随项目的启动而创建,随项目关闭而销毁
①拦截器创建
方法一:实现Interceptor接口并实现其三个方法
public class MyInterceptor implements Intercepter{}

方法二:继承AbstractInterceptor
空实现了init 和 destory方法. 我们如果不需要实现这两个方法,就可以只实现intercept方法
public class MyInterceptor2 extends AbstractInterceptor {}

方法三:继承MethodFilterInterceptor 方法过滤拦截器并复写doIntercept方法
//功能: 定制拦截器拦截的方法.  定制哪些方法需要拦截、哪些方法不需要拦截
public class MyInterceptor3 extends MethodFilterInterceptor{
	doIntercept(ActionInvocation invocation){
		放行+前后处理:
		//前处理
		invocation.invoke();
		//后处理
		//不处理直接放行
		return invocation.invoke();
		不放行,直接跳转到一个结果页面
		return "success";//不执行后续的拦截器以及Action,直接交给Result处理结果.进行页面跳转
	}
}

②配置struts.xml,在default.properties中可以找到相应的默认配置
注册拦截器<interceptor name="" class=""></interceptor>

定制拦截方法并配置拦截器栈
<interceptor-stack name="myStack">
	<!-- 自定义拦截器引入(建议放在20个拦截器之前) -->
	<interceptor-ref name="myInter3">
		<!-- 指定哪些方法不拦截
		<param name="excludeMethods">add,delete</param> -->
		<!-- 指定哪些方法需要拦截 -->
		<param name="includeMethods">add,delete</param>
	</interceptor-ref>
	<!-- 引用默认的拦截器栈(20个) -->
	<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>

指定包中默认拦截器栈<default-interceptor-ref name="myStack"></default-interceptor-ref>

Action指定拦截器
<action name="Demo1Action_*" class="cn.interceptor.Demo1Action" method="{1}" >
	<!-- 为Action单独指定走哪个拦截器(栈) 
	<interceptor-ref name="myStack"></interceptor-ref>-->
	<result name="success" type="dispatcher" >/index.jsp</result>
</action>

12. struts2标签(了解)

	控制标签
	遍历标签 iterator 
	<s:iterator value="#list" >
		<s:property /><br>
	</s:iterator>

	<s:iterator value="#list" var="name" >
		<s:property value="#name" /><br>
	</s:iterator>

	<s:iterator begin="1" end="100" step="1"  >
		<s:property />
	</s:iterator>

	if标签
	<s:if test="#list.size()==4">
		list长度为4!
	</s:if>
	<s:elseif test="#list.size()==3">
		list长度为3!
	</s:elseif>
	<s:else>
		list不3不4!
	</s:else>
	判断boolean值不要自己用==true判断

	数据标签
	<!--property 配合ognl表达式页面取值,Action没有返回数据时没有值-->
	<s:property value="#list.size()" />
	<!--获得session中的值,常用于表达登录用户信息-->
	<s:property value="#session.user.name" />

	表单标签
	<!-- 好处1: 内置了一套样式.  - 好处2: 自动回显,根据栈中的属性  -->
	<!-- theme:指定表单的主题,就是表单的style,xhtml:默认,simple:没有主题-->
	<s:form action="Demo3Action" namespace="/" theme="xhtml" >
		<s:textfield name="name" label="用户名"  ></s:textfield>
		<s:password name="password" label="密码" ></s:password>
		<s:radio list="{'男','女'}" name="gender" label="性别" ></s:radio>
		<s:radio list="#{1:'男',0:'女'}" name="gender" label="性别" ></s:radio>
		<s:checkboxlist list="#{2:'抽烟',1:'喝酒',0:'烫头'}" name="habits" label="爱好" ></s:checkboxlist>
		<s:select list="#{2:'大专',1:'本科',0:'硕士'}" headerKey="" headerValue="---请选择---" name="edu" label="学历" ></s:select>
		<s:file name="photo" label="近照" ></s:file>
		<s:textarea name="desc" label="个人简介" ></s:textarea>
		<s:submit value="提交" ></s:submit>
	</s:form>

	非表单标签
	在action中添加错误信息this.addActionError("你错了");
	取出错误信息<s:actionerror>
	<s:debug></s:debug>

13. 表现层抽取

	//表现层通用实现
	public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
		//模型对象
		private T model;
		public T getModel() {
			return model;
		}
		
		//在构造方法中动态获取实体类型,通过反射创建model对象
		public BaseAction() {
			ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
			//获得BaseAction上声明的泛型数组
			Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
			Class<T> entityClass = (Class<T>) actualTypeArguments[0];
			//通过反射创建对象
			try {
				model = entityClass.newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

14. 文件上传

	<!-- 文件上传页面三个要求:
	表单必须post提交,
	表单提交类型,必须多项式,
	文件上传使用<input type="file"/>组件 -->
	<FORM id=form1 name=form1
	action="${pageContext.request.contextPath }/CustomerAction_add"
	method="post" enctype="multipart/form-data">
	<input type="file" name="photo"/>
	</FORM>
	//上传的文件自动封装到File对象,
	//只需后台提供一个FIle属性且名字与前台file的name属性名相同的字段
	private File photo;
	//在提交键名后加上固定后缀FIleName,文件名会自动封装到属性中
	private String photoFileName;
	//在提交键名后加上固定后缀ContentType,文件MIME类型会自动封装到属性中
	//image/jpeg等
	private String photoContentType;
	set/get方法

	//测试上传,上传文件保存到指定位置
	//默认保存到?
	photo.renameTo(new File("F:/testupload/test.jpg"));

15. 处理Ajax请求

public String fun(){
	通过ServletAPI方式		
	/*使用jsonlib将pageBean转为json,通过输出流写回页面中 
	JSONObject将单一对象转为json,不用看里面是什么,主要看本来的性质
	JSONArray将数组或者集合对象转为json*/
	JsonConfig jsonConfig = new JsonConfig();
	jsonConfig.setExcludes(new String[] {"currentPage","detachedCriteria","pageSize"});
	String json = JSONObject.fromObject(pageBean).toString();

	//ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
	ServletActionContext.getResponse().setContentType("text/html;charset=utf-8");
	ServletActionContext.getResponse().getWriter().print(f);
	return null;
}

总结

本文介绍了的struts2使用,如有问题欢迎私信和评论

  • 19
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程流年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值