文章目录
- 1. struts2访问流程&架构&介绍
- 2. 搭建struts2框架
- 3. strust.xml配置详解
- 4. Action生命周期
- 5. ActionContext内容
- 6. 访问servletAPI方式
- 7. jsp获得
- 8. Action接收参数
- 9. struts、hibernate的javassist-3.18.1-GA.jar包重复,删除版本低的.
- 10. OGNL表达式
- 10.1. OGNL与Struts2的结合原理
- 10.2. struts2与ognl结合体现
- 11. 自定义拦截器
- 12. struts2标签(了解)
- 13. 表现层抽取
- 14. 文件上传
- 15. 处理Ajax请求
- 总结
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:对象视图导航语言. ${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使用,如有问题欢迎私信和评论