1 重点
Ø 掌握struts2开发环境搭建
Ø 学会使用struts2完成登录案例
Ø 掌握struts.xml配置文件标签的含义
Ø 掌握Action的创建及访问
2
2.1 struts2框架介绍
struts2框架是一个MVC框架。
1.1 要实现的案例分析与说明
Ø 使用Servlet实现
Ø 使用Struts2实现
1.1 使用Servlet实现登录案例
1.1.1 创建JSP页面
Ø login.jsp
<formaction="${pageContext.request.contextPath}/login"method="post">
用户名: <inputname="username"/>
密码:<inputname="password"type="password"/>
<inputtype="submit"value="提交"/>
</form>
Ø success.jsp
在页面中显示“登录成功”
Ø fail.jsp
在页面中显示“登录失败”
1.1.2 创建LoginServlet
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
}
protected void doGet(HttpServletRequest request,HttpServletResponseresponse)throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request,HttpServletResponseresponse)throws ServletException, IOException {
// 接收JSP页面中传递的参数
// 注意:此处的参数名称要与<input>标签中的name保持一致
String userName = request.getParameter("username");
String password = request.getParameter("password");
if(userName.equals("tom") &&password.equals("123")) {
// 跳转到success.jsp页面
response.sendRedirect("success.jsp");
}
else {
// 跳转到fail.jsp页面
response.sendRedirect("fail.jsp");
}
}
}
1.1.3 在web.xml中配置LoginServlet
<servlet>
<servlet-name>LoginServlet</servlet-name>
<!-- 指定LoginServlet的类名 -->
<servlet-class>com.itheima.struts2.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<!-- 指定LoginServlet的访问路径 -->
<url-pattern>/login</url-pattern>
</servlet-mapping>
Ø 将项目添加到Tomcat,启动Tomcat。使用http://localhost:8080/s2_01/login.jsp访问登录页面
2
2.1 struts2框架要解决的问题
2.1.1 为什么要使用struts2框架?
struts2已经实现了MVC框架。我们可以重点关注在业务逻辑上。
2.1.2 struts2开发流程(掌握)
(1) 导入Struts2所需要的JAR包
(2) 在web.xml中配置struts2的核心filter
(3) struts.xml配置
(4) 创建Action来完成逻辑操作
2.1.3 struts2框架文档结构
apps:示例代码
docs:文档
user guide(reference)
javadoc
lib:Struts2相关的JAR包
src:struts2的源代码
2.2 struts2环境搭建(掌握)
Ø 导入JAR包
ž 解压apps目录下的struts-blank文件
ž 拷贝struts-blank目录下WEB-INF\lib中的所有JAR包
Ø 在web.xml中配置Struts2的核心Filter(只有配置了该FilterStruts2才能生效)
<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>
Ø 创建struts.xml,并将struts.xml添加到src目录下(该文件可以直接从apps\struts2-blank\WEB-INF\classes直接拷贝)
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTDStruts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
</struts>
2.3 struts2快速入门(掌握)
Ø 导入JAR包
Ø 在web.xml中添加struts2的核心Filter
Ø 添加struts.xml到src目录
Ø 编写Action
Ø 将编写的Action配置到struts.xml中
2.4 struts2执行流程分析
1.1 struts2完成简单登录案例(掌握)
1.1.1 开发流程
Ø 创建页面
login.jsp、success.jsp、fail.jsp
Ø 创建LoginAction
public class LoginAction {
// 这两个变量是用来接收前台表单传递的数据
private Stringusername;
private Stringpassword;
public String login() {
if(username.equals("tom") &&
password.equals("123")) {
return"success";
}
else {
return"fail";
}
}
// 必须提供setter来接收前端的数据
public void setUsername(String username) {
this.username =username;
}
public void setPassword(String password) {
this.password =password;
}
}
注意:
(1) 要接收前端传递过来的参数,需要在Action类中提供成员变量,并为其提供get/set方法。
(2) setter方法的名称需要与表单中的<input>的name匹配,否则Action将无法接收到参数。
例如:input标签的name属性分别为username,password
<formaction="${pageContext.request.contextPath}/login"method="post">
用户名: <inputname="username"/>
密码:<inputname="password"type="password"/>
<inputtype="submit"value="提交"/>
</form>
对应的Action需要提供setUsername、setPassword来接收。命名规则为:set+ <input>标签name(首字母大写)
public void setUsername(Stringusername) {
this.username =username;
}
public void setPassword(Stringpassword) {
this.password =password;
}
Ø 配置struts.xml
name:访问该Action的URL
class:对应Action类的完全限定名称
method:要执行的方法名称
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEstrutsPUBLIC
"-//ApacheSoftware Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<packagename="default"extends="struts-default"namespace="/">
<actionname="login"class="com.itheima.web.action.LoginAction"method="login">
<resultname="success">/success.jsp</result>
<resultname="fail">/fail.jsp</result>
</action>
</package>
</struts>
result中的name属性需要与Action中方法的返回值一致才能正确跳转。
1.1.2 执行过程分析
(1) 浏览器发起请求
(2) Struts2的核心过滤器拦截到该请求
(3) Struts2根据struts.xml调用LoginAction类的login方法
(4) 根据login返回的字符串找到对应要跳转到的页面
1 第三节课
1.1 struts2源代码导入
struts2中的源代码分为三个部分:
Ø struts2核心部分源代码(包名以org.apache.struts2开头)
src\core\src\main\java
Ø struts2的xwork核心源代码(包名以com.opensyphony开头)
src\xwork-core\src\main\java
Ø struts2插件源代码
plugins\json\src\main\java
导入struts2源代码:
Ø 选择查看struts2中某个类(eclipse按住ctrl键 + 鼠标左键)
选择源码目录
参考:src/core/src/main/java
1.1 解决struts2.xml文件不提示问题
eclipse选择window下的preferences
Ø 点击添加
Location从文件系统中选择dtd文件路径,在struts2下的src\core\src\main\resource下有
Key type选择为URI
Key为:http://struts.apache.org/dtds/struts-2.3.dtd
1.1 struts2框架执行流程
(1) 浏览器发起请求
(2) StrutsPrepareAndExecuteFilter拦截
(3) 调用struts2默认拦截器完成部分功能
(4) 根据struts.xml调用指定Action
(5) 执行Action中的操作
(6) 根据Action中方法的返回值选择要跳转到的页面
1.1 struts2加载配置文件的顺序
(1) 加载default.properties文件 加载常量的配置文件
位置:strtus2-core.jar包 org.apache.struts2包下
作用:主要是声明了struts2框架的常量
(2) 加载一批配置文件
a) struts-default.xml
位置:struts2-corl.jar
作用:声明了interceptor(拦截器) result(结果集) bean
a) struts-plugin.xml
位置:在strtus2的插件包中(需要去资料包里面找)
作用:主要用于插件的配置声明
b) struts.xml
位置:在我们自己的工程中
作用:用于我们自己工程使用strtus2框架的配置
(2) 加载自定义的struts.properties
位置:都是在自己工程的src下
作用:定制常量
(3) 自定义配置提供
(4) 加载的是web.xml配置文件
a) 主要是加载struts2框架在web.xml中的配置
(5) bean相关配置
1.1 struts.xml配置文件(掌握)
<packagename="default"extends="struts-default"namespace="/user">
<actionname="login"class="com.itheima.web.action.LoginAction"method="login">
<resultname="success">/success.jsp</result>
<resultname="fail">/fail.jsp</result>
</action>
</package>
1.1.1 package
Ø name属性:包的唯一标识.package用来管理action的 , action必须在package里面,
Ø namespace属性:与Action标签的name属性联合使用来确定一个Action的访问路径
上面的action的访问路径为:/user/login
Ø extends属性:指定继承自哪个包。一般配置为struts-default。这个包在struts-default.xml文件中定义。
Ø abstract属性:代表当前包是抽象来,用来被其他包继承
1.1.2 action
Ø name属性:与package的namespace联合使用来确定Action的访问路径
Ø class属性:用于指定Action类
Ø method属性:用于指定当前类执行哪个方法
1.1.3 result
用于指定结果视图
1.name属性:与action类的method方法的返回值进行匹配,来确定跳转路径
2.type属性:用于指定跳转方式。redirect:重定向(URL会变成新的页面),不设置的话默认是请求转发(URL不变)
2 第四节课
2.1 配置默认action、默认method (就是在配置中不写它)
<packagename="default"extends="struts-default"namespace="/">
<actionname="test">
<result>/success.jsp</result>
</action>
</package>
URL访问该action,会转发到success.jsp
2.1.1 默认配置
关于action配置中的class与method的默认值以及result中的name与type 默认值问题
struts-default包中定义了默认的class为
<default-class-refclass="com.opensymphony.xwork2.ActionSupport"/>
它的作用就是当一个请求来时,如果查找不到指定的class及对应的method就会执行
ActionSupport类中的execute方法。
在这个类的execute方法中默认返回的是”success”
也就是说,result的name属性默认值是success,默认的跳转方式是请求转发 dispatcher
如果class指定为自己建的类, 但是method没有指定的时候 , 执行会报错, 但是此时我们由上原理可以在自己的类中添加一个execute()方法 , 那么即使没有指定method方法系统也会自动执行我们在类中建的execute方法.
默认的result-type为dispatcher
<result-types>
<result-typename="chain"class="com.opensymphony.xwork2.ActionChainResult"/>
<result-typename="dispatcher"class="org.apache.struts2.dispatcher.ServletDispatcherResult"default="true"/>
<result-typename="freemarker"class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-typename="httpheader"class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-typename="redirect"class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-typename="redirectAction"class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-typename="stream"class="org.apache.struts2.dispatcher.StreamResult"/>
<result-typename="velocity"class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-typename="xslt"class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-typename="plainText"class="org.apache.struts2.dispatcher.PlainTextResult"/>
<result-typename="postback"class="org.apache.struts2.dispatcher.PostbackResult"/>
</result-types>
Ø 默认Action的方法为execute
Ø result默认的name为success
2.2 定义struts2常量
struts2-core.jar中的org.apache.struts2包下的default.properties文件中定义了struts2框架的常用常量。
2.2.1 在src下创建struts.properties文件(了解)
struts.i18n.encoding=UTF-8
struts.action.extension=action,,
struts.devMode=true
2.2.2 在web.xml配置
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>struts.i18n.encoding</param-name>
<param-value>US-ASCII</param-value>
</init-param>
</filter>
2.2.3 直接在struts.xml中定义(常用)
<constantname="struts.i18n.encoding"value="UTF-8"></constant>解决post请求乱码
<constantname="struts.action.extension"value="action,,"></constant> 指定struts2处理的路径后缀名
<constantname="struts.devMode"value="true"></constant>
提供更加详细的报错信息, 以及struts.xml文件修改后不再需要重启服务器.
<package name=”struts2”namespace=”cndfefefefef” extends=”struts-default”>
当路径后缀名设置为action的 时候Jsp页面请求的路径为action时候才能解析. 为action,,表示不写后缀都能处理.
注意:后加载的配置文件会覆盖先加载的常量(default.properties→ struts-default.xml →struts.xml →struts.properties → web.xml)
1.1 Action详解:创建Action的三种方式
Struts2中的action,主要是完成业务逻辑操作。Action替代在servlet中完成的作用。
Action的学习主要有两点
1. 如何创建一个struts2的action
2. 如果访问一个struts2的action
1.1.1 POJO类
Pojo(plain Old java object)简单的java对象
POJO类为没有实现任何接口、没有继承任何类
优点:不耦合struts2
缺点:所有功能都需要自己完成
public class Action1 {
public String execute() {
return"success";
}
}
1.1.2 实现Action接口
com.opensymphony.xwork2.Action
Action接口中定义了5个常量和execute方法
五个常量:它们是默认的五个结果视图<result name=””>:
ERROR:Action执行失败,返回到错误处理视图
INPUT:Action执行需要从前端界面中获取参数,struts2会对这些参数进行验证,如果验证没有通过,则自动返回到该视图
LOGIN:登录视图,可以在权限操作中使用
NONE:表示Action正确的执行完成,但并不返回任何视图
SUCCESS:Action正确的执行完成,返回相应的视图,success是name属性的默认值
public class Action2 implements Action{
@Override
public String execute()throws Exception {
return SUCCESS;
}
}
1.1.3 继承ActionSupport类(掌握)
开发中常用
优点:具有丰富的功能,例如:表单校验、错误信息设置、国际化
缺点:耦合度较高
public class Action3 extends ActionSupport{
}
struts.xml
<packagename="default"extends="struts-default"namespace="/">
<actionname="action1"class="com.itheima.web.action.Action1">
<result>/success.jsp</result>
</action>
<actionname="action2"class="com.itheima.web.action.Action2">
<result>/success.jsp</result>
</action>
<actionname="action3"class="com.itheima.web.action.Action3">
<result>/success.jsp</result>
</action>
</package>
测试代码:在登录页面的jsp中修改提交路径来测试;
: <formaction="${pageContext.request.contextPath}/action3"method=''post>
1.2 访问Action的方式
1.直接通过<action>标签来配置,通过method来指定访问的方法,如果method没有,默认访问的是execute方法。
2.简化的action访问方式,可以使用*通配符来访问。
这种方式的缺点:不建议使用过多的*号,它带来程序阅读障碍,不便于理解
使用*来简化操作方案,它对名称规范必须进行一个统一。
public class UserActionextends ActionSupport{
public String add() {
syso(“add”)
return SUCCESS;
}
public String update() {
syso(“update”)
return SUCCESS;
}
public String delete() {
syso(“delete”)
return SUCCESS;
}
public String query() {
syso(“query”)
return SUCCESS;
}
}
1.2.1 直接通过<action>标签来配置
通过method来指定访问的方法,如果没有method,默认访问的execute
<actionname="user-add"class="com.itheima.web.action.UserAction"method="add">
<resulttype="redirect">/user-success.jsp?method=add</result>
</action>
测试代码:就是在jsp页面中的提交路径修改为user-add,然后地址栏输入为
http://localhost:8080/mystruts2-day01/user-add,然后我们就可以看到控制台输出add并且页面跳转到登录成功页面
1.2.2 通过通配符来配置
<packagename="default"extends="struts-default"namespace="/">
<actionname="user-*"class="com.itheima.web.action.UserAction"method="{1}">
<resulttype="redirect">/user-success.jsp?method={1}</result>
</action>
</package>
测试代码:就是在jsp页面中的提交路径修改为user-add,然后地址栏输入为
http://localhost:8080/mystruts2-day01/user-update,然后我们就可以看到控制台输出update并且页面跳转到登录成功页面.
注意:获取通配符索引是从{1}开始,不要写成{0}
2 第五节课
2.1 使用动态方法调用访问Action
通过URL来指定要执行Action的方法
Ø 开启动态方法调用(DynamicMethod Invocation)(在struts.xml中去添加开启)
<constantname="struts.enable.DynamicMethodInvocation"value="true"></constant>
并且配置一个Action标签
<actionname="user"class="action.UserAction">
<result>/success.jsp</result>
</action>
Ø 通过URL访问Action
http://localhost:8080/s2_08/user!add
user:Action配置的name
add:Action类中的方法
2.2 struts2封装数据的方式(掌握)
如何在Action(也就是实现跳转的Action类)中接收前端传递的数据。
主要有两种方式:
1.属性驱动
a.直接在action类中提供与请求参数匹配属性,提供get/set方法
b.在action类中创始一个javaBean,对其提供get/set ,在请求时页面上要进行修改, 例如 user.username user.password,要使用ognl表达式
以上两种方式的优缺点:
第一种比较简单,在实际操作我们需要将action的属性在赋值给模型(javaBean) 去操作
第二种:不需要在直接将值给javaBean过程,因为直接将数据封装到了javaBean 中。它要求在页面上必须使用ognl(Object-GraphNavigation Language)表达式,就存在页面不通用问题。
2.模型驱动
步骤:
1.让Action类要实现一个指定接口ModelDriven
2.实例化模型对象(就是要new出来javaBean)
3.重写getModel方法将实例化的模型返回。
2.2.1 属性驱动
Ø 第一种在action类中提供与请求参数匹配的字段,提供对应的getter/setter方法
JSP表单页面
<formaction="${pageContext.request.contextPath}/user1"method="post">
用户名: <inputname="username"/>
密码:<inputname="password"type="password"/>
<inputtype="submit"value="提交"/>
</form>
Action
public class UserAction1 extends ActionSupport{
private Stringusername;
private Stringpassword;
@Override
public Stringexecute()throws Exception {
System.out.println(username +" " +password);
return NONE;
}
public String getUsername() {
returnusername;
}
public void setUsername(String username) {
this.username =username;
}
public String getPassword() {
returnpassword;
}
public void setPassword(String password) {
this.password =password;
}
}
测试代码:
在struts.xml中配置:
<actionname="user1"class="action.UserAction1"></action>
将login.jsp的跳转路径配置为:
<formaction="${pageContext.request.contextPath }/user1"method=''post>
然后开启服务器,进login.jsp提交后就能在控制台看到我们输入的用户名和密码了.说明完成了数据封装.
因为有动态方法调用, 所以能够完成整套跳转.
Ø 第二种在Action类中创建一个JavaBean,并提供对应的getter/setter
Java Bean
public class User {
private Stringusername;
private Stringpassword;
public String getUsername() {
returnusername;
}
public void setUsername(String username) {
this.username =username;
}
public String getPassword() {
returnpassword;
}
public void setPassword(String password) {
this.password =password;
}
@Override
public String toString() {
return"User [username=" +username + ", password=" +password + "]";
}
}
JSP表单页面
<formaction="${pageContext.request.contextPath}/user2"method="post">
用户名: <inputname="user.username"/>
密码:<inputname="user.password"type="password"/>
<inputtype="submit"value="提交"/>
</form>
Action
public class UserAction2 extends ActionSupport{
private Useruser;
@Override
public String execute()throws Exception {
System.out.println(user);
return NONE;
}
public User getUser() {
returnuser;
}
public void setUser(User user) {
this.user =user;
}
}
在struts.xml中配置:
<actionname="user2"class="action.UserAction2"></action>
将login.jsp的跳转路径配置为:
<formaction="${pageContext.request.contextPath }/user2"method=''post>
然后开启服务器,进login.jsp提交后就能看到控制台输出:
User [username=12345, password=dalaohu]
2.2.2 模型驱动
直接将数据封装到一个模型中,但一次只能对一个模型进行封装。
Ø Action类实现ModelDriven<T>接口
Ø 实例化模型对象(就是new出来)
Ø 重写getModel方法,返回实例化的模型对象
JSP页面
<formaction="${pageContext.request.contextPath}/user3"method="post">
用户名: <inputname="username"/>
密码:<inputname="password"type="password"/>
<inputtype="submit"value="提交"/>
</form>
Action
public class UserAction3 extends ActionSupportimplementsModelDriven<User>{
private Useruser =new User();
@Override
public String execute()throws Exception {
System.out.println(user);
return NONE;
}
@Override
public User getModel() {
returnuser;
}
}
测试代码:
在struts.xml中配置:
<actionname="user3"class="action.UserAction3"></action>
将login.jsp的跳转路径配置为:
<formaction="${pageContext.request.contextPath }/user3"method=''post>
然后开启服务器,进login.jsp提交后就能看到控制台输出:
User [username=ladys, password=gentleman]
对于模型驱动它与属性驱动对比,在实际开发中使用比较多,模型驱动缺点,它只能对 一个模型数据进行封装
2.3 关于路径跳转问题:
是通过<result>来配置跳转的路径.
它的name属性是与action中的方法的返回值进行对比的。
它的type属性可以取哪些值?
struts-default.xml中定义了许多的result-type
<result-types>
<result-typename="chain"class="com.opensymphony.xwork2.ActionChainResult"/>
<result-typename="dispatcher"class="org.apache.struts2.dispatcher.ServletDispatcherResult"default="true"/>
<result-typename="freemarker"class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-typename="httpheader"class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-typename="redirect"class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-typename="redirectAction"class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-typename="stream"class="org.apache.struts2.dispatcher.StreamResult"/>
<result-typename="velocity"class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-typename="xslt"class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-typename="plainText"class="org.apache.struts2.dispatcher.PlainTextResult"/>
<result-typename="postback"class="org.apache.struts2.dispatcher.PostbackResult"/>
</result-types>
ž dispatcher:请求转发到页面(JSP)
HttpServletRequestrequest = ServletActionContext.getRequest();
HttpServletResponseresponse = ServletActionContext.getResponse();
RequestDispatcher dispatcher =request.getRequestDispatcher(finalLocation);
.....
if (!insideActionTag && !response.isCommitted()&&(request.getAttribute("javax.servlet.include.servlet_path")==null)){
request.setAttribute("struts.view_uri", finalLocation);
request.setAttribute("struts.request_uri", request.getRequestURI());
dispatcher.forward(request,response);
}
ž redirect:重定向页面
if (SC_FOUND ==statusCode) {
response.sendRedirect(finalLocation);
} else {
response.setStatus(statusCode);
response.setHeader("Location",finalLocation);
response.getWriter().write(finalLocation);
response.getWriter().close();
}
ž chain:转到Action
获取要转发到的Action的(namespace、action、method),重新创建Action,并执行Action中的方法。
public void execute(ActionInvocation invocation)throws Exception {
// if the finalNamespace wasn't explicitly defined, assume the current one
if (this.namespace ==null) {
this.namespace =invocation.getProxy().getNamespace();
}
ValueStack stack = ActionContext.getContext().getValueStack();
String finalNamespace = TextParseUtil.translateVariables(namespace,stack);
String finalActionName = TextParseUtil.translateVariables(actionName,stack);
String finalMethodName =this.methodName !=null
? TextParseUtil.translateVariables(this.methodName,stack)
: null;
……..
HashMap<String,Object> extraContext =new HashMap<String, Object>();
extraContext.put(ActionContext.VALUE_STACK, ActionContext.getContext().getValueStack());
extraContext.put(ActionContext.PARAMETERS, ActionContext.getContext().getParameters());
extraContext.put(CHAIN_HISTORY, ActionChainResult.getChainHistory());
if (LOG.isDebugEnabled()) {
LOG.debug("Chaining to action " +finalActionName);
}
proxy =actionProxyFactory.createActionProxy(finalNamespace,finalActionName,finalMethodName,extraContext);
proxy.execute();
}
ž redirectAction:重定向到Action
与redirect类似,它是跳转到Action
dispatcher 是默认值的跳转方式,它代表的是请求转发。针对于jsp页面
redirect 它代表的是重定向 针对于jsp页面
chain 它类似于请示转发,只不过它是针对于action跳转.
redirectAction 它类似于重定向 针对于action
补充:
当一个package中的很多个action跳转到路径都是相同的 , 可以抽取配置成一个全局的跳转路径result如下:
<global-results>
<resultname=""type=""></result>
</global-results>