(二)、Struts第二天

()Struts第二天

回顾:

问题:

1. Struts2Action类是单例还是多例? Filter? Servlet? Listener?

2. 介绍struts2框架引入的相关jar包及作用?

3. Struts2 配置文件中,名称空间作用?

4. Struts2 执行流程

 

目标:

0. Action类的几种写法

1. Struts核心配置

常量配置

通配符/动态方法调用

全局视图、全局异常、Action配置各项的默认值

2. 拦截器

 

1. Action类的几种写法

1。 搭建struts开发环境

2.  Action类、配置Action

 

 

开发Action:

1. 写一个普通的java类;

2. 写一个普通的java实现Action接口 【可以使用常量】

3. 写一个普通的java类;继承ActionSupport类    【常用; 】

         如果使用struts提供的数据效验功能,必须继承ActionSupport!

 

public class DemoAction {}

public class DemoAction implements  Action {}

public class DemoAction extends ActionSupport {}

2. 通配符

语法如: user_*      * 的值由访问时候传入的值确定;

引用的时候,用{1}引用*的值

 

传统的写法,

 

<!-- 访问:  http://localhost:day28/save.action

方式1:传统的写法

<action name="save" class="cn.itcast.a_action.DemoAction" method="save">

<result name="save">/a/save.jsp</result>

</action>

<action name="delete" class="cn.itcast.a_action.DemoAction" method="delete">

<result name="delete">/a/delete.jsp</result>

</action>

<action name="update" class="cn.itcast.a_action.DemoAction" method="update">

<result name="update">/a/update.jsp</result>

</action>

 -->

 

 

使用通配符优化配置

<!-- 

方式2:使用通配符优化配置

访问:  http://localhost:day28/demo_save.action

访问:  http://localhost:day28/demo_update.action

 -->

<action name="demo_*" class="cn.itcast.a_action.DemoAction" method="{1}">

<result name="{1}">/a/{1}.jsp</result>

</action>

 

特殊的用法,

<!-- 

注意:

访问1: http://localhost:8080/day28/demo_execute

     如果方法返回的是success,可以省略名称

      <result name=success>/index.jsp</result>  

      <result>/index.jsp</result>        同上

方式2http://localhost:8080/day28/demo

要求: 

1. 必须有execute方法默认找execute方法

2. execute方法,必须返回success;

 -->

<action name="demo_*" class="cn.itcast.a_action.DemoAction" method="{1}">

<result>/index.jsp</result>

</action>

 

 

3. 动态方法调用(了解)

<!-- 

  另外的方式:

  动态方法调用:

  语法: !  感叹号后面的就是要处理的Action类中的方法名称!

  举例: 

  http://localhost:8080/day28/demo!save

  表示actionName demo对应的Action类,必须有一个save方法!

    

            动态方法调用与通配符区别?

      1. 配置

       通配符是用与 {1}  配合使用

       动态方法调用是在访问的时候通过!符合指定方法名称

      2. 比较

       建议使用通配符! 不要用动态方法调用! (相对不安全!)

       开发中都会禁用这个功能!

  -->

 <action name="demo" class="cn.itcast.a_action.DemoAction">

<result>/index.jsp</result>

<result name="save">/a/save.jsp</result>

<result name="update">/a/update.jsp</result>

<result name="delete">/a/delete.jsp</result>

</action>

 

4. 全局相关配置

 

全局视图、全局异常、配置各项默认值!

<?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_new" extends="struts-default">

<!-- 4. 默认执行的action类 -->

<!-- 测试:指定默认执行的action类! 会覆盖调struts-default.xml中默认执行的Action(ActionSupport) -->

<default-class-ref class="cn.itcast.b_config.DefaultAction"></default-class-ref>

<!-- 

1. 全局跳转视图配置

这里面的配置,可以供当前包下所有的action共享!

 -->

 <global-results>

  <result name="success">/index.jsp</result>

  <result name="error">/error.jsp</result>

 </global-results>

 

 <!-- 

  2. 全局异常配置

  当此包下的action类执行出现空指针异常,会取找error对应的全局视图对应的页面进行跳转!

  -->

 <global-exception-mappings>

  <exception-mapping result="error" exception="java.lang.NullPointerException"></exception-mapping>

 </global-exception-mappings>

 

<action name="user_*" class="cn.itcast.b_config.UserAction" method="{1}">

</action>

 

<action name="order_*" class="cn.itcast.b_config.OrderAction" method="{1}">

</action>

<!-- 

3. 各项目配置默认值

name  访问路径资源

class 默认执行的Action类是:ActionSupport!

   在struts-default.xml配置文件中配置,

<default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> 

 表示默认执行的action类! 用户开发时候,可以在自己的package中进行配置,那么会覆盖父类的配置!

 

  method 默认执行execute方法

                       且返回success, 但当前没有配置对应页面,所以会取找全局视图配置!

--> 

<action name="test"></action>

<!-- 作用:可以跳转到WEB-INF下资源,但不用写Action类!

<action name="test">

<result name="success">/WEB-INF/index.jsp</result>

</action>

 -->

 

</package>

 

</struts>

 

 

 

5. 常量配置

思考:struts2访问后缀能否修改?

-à 先找到定义的位置

-à 定义自己设置的后缀,覆盖默认

 

 

常量定义位置:

struts2-core-2.3.4.1.jar/org.apache.struts2/default.properties

struts.xml中定义常量:

<constant name=" " value=" "/>

 

 

    指定默认编码集,作用于HttpServletRequestsetCharacterEncoding方法 和freemarker velocity的输出 

    <constant name="struts.i18n.encoding" value="UTF-8"/>

    自定义后缀修改常量 

    <constant name="struts.action.extension" value="do"/>

    设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭 

    <constant name="struts.serve.static.browserCache" value="false"/>

    struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开 

    <constant name="struts.configuration.xml.reload" value="true"/>

    开发模式下使用,这样可以打印出更详细的错误信息 

    <constant name="struts.devMode" value="true" />

    默认的视图主题 

    <constant name="struts.ui.theme" value="simple" />

    spring集成时,指定由spring负责action对象的创建 

    <constant name="struts.objectFactory" value="spring" />

    该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性

    为 false

    <constant name="struts.enable.DynamicMethodInvocation" value="false"/>

    上传文件的大小限制 

    <constant name="struts.multipart.maxSize" value=“10701096"/>

 

 

 

6. 数据处理

方式1ActionContext 获取表示域对象的map

这样就可以通过操作map来操作域对象!

方式2: 实现接口的方式, 获取表示域对象的map集合!

RequestAware/SessionAware/ApplicationAware

原理:servletConfig拦截器!注入的map是从ActionContext对象获取的map!

方式3ServletActionContext 获取原始的ServletApi

 

 

(一) 方式2实现:

 

/**

 * 所有的action可以继承此类,就可以直接用map集合  保存数据!

 * @author AdminTH

 *

 */

public class BaseAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware {

protected Map<String, Object> request;

protected Map<String, Object> session;

protected Map<String, Object> application;

// 在运行时期(servletConfig拦截器), struts会把表示requestmap注入进来!

@Override

public void setRequest(Map<String, Object> request) {

this.request = request;

}

// 在运行时期(servletConfig拦截器), struts会把表示sessionmap注入进来!

@Override

public void setSession(Map<String, Object> session) {

this.session = session;

}

// 在运行时期(servletConfig拦截器), struts会把表示applicationmap注入进来!

@Override

public void setApplication(Map<String, Object> application) {

this.application = application;

}

}

 

 

(二) 方式2实现原理:

 

Struts-defualt.xml 中关于servletConfig拦截器!

 

 

 

 

 

7. 用户库

MyEclipse如何管理jar文件?

答案:用户库!

 

使用步骤:

1. 新建用户库

--à选中项目,右键,properties

-àLibrary,   右侧Add Library

-à ……

 

2. 发布项目

检查tomcat下是否有用户库的jar包!

如果有,直接启动!

 

 

注意:

如果用户库中的jar包没有发布到tomcat下,按照

《构建用户库-步骤图解.doc》 操作!

 

 

8. 共性问题

问题1: Struts.xml没有提示?

 

解决a: 配置MyEclipse关联约束!

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

"http://struts.apache.org/dtds/struts-2.3.dtd">

 

步骤:

1. 源码找到文件: struts-2.3.dtd存到到指定目录(E:DTD

2. Windows-à Preferences -à XML Catalog

Location: 定位到dtd文件的目录路径(如:E:DTD)

Key:  -//Apache Software Foundation//DTD Struts Configuration 2.3//EN

3. OK; 关闭XML; 重新打开! 

 

解决b: 连接internet即可! 工具会自动下载!

或者,

手写!

 

 

 

 

问题2: @Override 报错?

 

解决1. 

@Override  删除即可!

解决2. 或者,

修改编译环境为1.6以上的环境!

 

JDK1.5 只支持对父类方法的@Override不支持接口的@Override

jdk1.6以后,接口的@Override就支持!

 

 

9. 拦截器

概念

Interceptor 表示拦截器!

 

1. Struts2通过一个拦截器完成一些通用的功能!用户使用哪些功能,自由组合即可!

2. Struts2总共定义了32个拦截器

Struts-defualt.xml中定义

3. 拦截器栈

引入一个个拦截器比较麻烦,可以定义一个栈里面包含多个拦截器;

那么使用的时候,只需要引入拦截器栈即可!

<interceptor-stack name="basicStack">

                <interceptor-ref name="拦截器1"/>  引用的拦截器

                <interceptor-ref name="拦截器1"/>

                <interceptor-ref name="拦截器1"/>

</interceptor-stack>

 

4. 默认执行的拦截器栈

    defaultStack为默认执行的拦截器栈;里面共引用了18个拦截器!

执行拦截器栈:

<default-interceptor-ref name="defaultStack"/>

注意:

如果用户没有指定执行哪个拦截器栈,“默认栈”就会被执行!

如果用户指定执行了哪个拦截器栈,默认的栈就不会被执行!

defaultStack strtus的基本功能,一般开发都会用到!

 

5. 面试题: 过滤器与拦截器区别?

共同点: 拦截器请求!

过滤器:

Servlet中的概念,可以拦截器所有的请求!

拦截器:

Struts2中的概念,只能拦截strutsaction的请求!

 

 

API & 配置

ü API

|-- interface Interceptor    拦截器接口!

|--abstract class  AbstractInterceptor   一般开发,可以直接继承这个类即可!

 

|-- interface   ActionInvocation   拦截器的执行状态

拦截器的依次调用,使用的就是这个对象!

 

 

接口核心3个方法:(filter类似)

void

destroy() 

 void

init() 

 String

intercept(ActionInvocation invocation) 

 

 

ü 配置

Struts-default.xml配置

 

1. 定义拦截器

<interceptors>

    

    1.1 定义每一个拦截器

    <interceptor name="abc" class=""/> 

    

    1.2 定义拦截器栈

    <interceptor-stack name="basicStack">

         <interceptor-ref name="abc"/>

    </interceptor-stack>

 

</interceptors>

 

2. 执行哪些拦截器(通过引用栈指定)

<default-interceptor-ref name="basicStack"/>

 

 

自定义拦截器

步骤:

1. 写一个普通java类,实现interceptor接口!

2. struts.xml配置拦截器

 

/**

 * 自定义拦截器

 * @author AdminTH

 *

 */

public class HelloInterceptor implements Interceptor{

// 启动时候,创建实例

public HelloInterceptor(){

System.out.println("1. 创建拦截器实例!");

}

 

// 启动后,创建实例之后执行初始化方法!

@Override

public void init() {

System.out.println("2. HelloInterceptor.init()");

}

 

// 拦截器业务处理方法在访问时候执行?

@Override

public String intercept(ActionInvocation invocation) throws Exception {

System.out.println("4. 拦截, 执行开始");

// 放行(去到下一个拦截器,如果没有下一个拦截器,就进入action)

String result = invocation.invoke();

System.out.println("6. 拦截, 执行结束");

return result;

}

@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="interceptor" extends="struts-default">

 <!-- 配置拦截器 -->

 <interceptors>

   <!-- 自定义的拦截器 -->

   <interceptor name="hello" class="cn.itcast.e_interceptor.HelloInterceptor"></interceptor>

   <!-- 定义拦截器栈 -->

   <interceptor-stack name="myStack">

    <!-- 引入默认的拦截器栈 -->

    <interceptor-ref name="defaultStack"></interceptor-ref>

    <!-- 自定义的拦截器 -->

<interceptor-ref name="hello"></interceptor-ref>    

   </interceptor-stack>

 </interceptors>

 <!-- 执行自定义的拦截器栈 -->

 <default-interceptor-ref name="myStack"></default-interceptor-ref>

 

 <action name="user_*" class="cn.itcast.e_interceptor.UserAction" method="{1}">

<result name="success">/test.jsp</result>

 </action>

 

</package>

 

</struts>

 

 

 

执行流程

服务器启动:

1. 创建拦截器实例

2. 执行init()初始化方法

用户访问Action

3. 创建Action实例

4. 执行拦截器intercept()方法

invocation.invoke();  表示进入下一个拦截器,或执行action

5. 进入action的业务方法,如execute()方法

6. execute()方法完成后,又一次回到执行各个拦截器

 

ActionInvocation 用法

// 拦截器业务处理方法在访问时候执行?

@Override

public String intercept(ActionInvocation invocationthrows Exception {

System.out.println("4. 拦截, 执行开始");

/*

 * 测试invocation的方法

 */

//1. 获取ActionContext对象

ActionContext ac = invocation.getInvocationContext();

//2. 获取当前拦截的action对象!

Object action = invocation.getAction();

//3. 获取action对象的代理对象

ActionProxy proxy = invocation.getProxy();

System.out.println(proxy.getActionName());  // 配置中action名称,即访问路径一部分

System.out.println(proxy.getMethod());      // 当前执行的方法!

System.out.println(proxy.getNamespace());   // 名称空间

String result = invocation.invoke();

System.out.println("6. 拦截, 执行结束");

return "error";

}

 

 

拦截器作用:

action的请求进行拦截,从而处理一些公用的业务逻辑操作!

那么action类中就可以直接用拦截器已经实现的功能了!

案例

1) 需求:

只有登陆后的用户,才可以查看“用户列表”!

功能:

1. 登陆

2. 列表展示

3. 权限控制

只有登陆,才能查看列表!

2) 实现步骤:

先做登陆、列表;

再增加“登陆验证功能”!

 

1. 环境准备

建库建表

项目使用组件

# struts2

# DbUtils组件

# C3p0连接池

# MySQL驱动包

# JdbcUtils工具类

 

2. entity 

User.java

3. dao

UserDao.java

Login();

List()

4. service

5. action

LoginAction

UserAction

6. login.jsp / list.jsp

 

7. “拦截器”实现登陆验证!

只有登陆后,才可以查看列表!

 

 

 

 

 

-- 建库

CREATE DATABASE day28 CHARACTER SET utf8;

 

USE day28;

day28

-- 建表

CREATE TABLE t_user(

  id INT PRIMARY KEY AUTO_INCREMENT,

  userName VARCHAR(20),

  pwd  VARCHAR(20),

  remark VARCHAR(200)

);

-- 录入测试数据

INSERT INTO t_user VALUES(1,'jack','888','好人');

INSERT INTO t_user VALUES(2,'rose','888','女人');

 

 

 

方式1: 在action配置标签体中,引入拦截器

拦截器代码:

 

/**

 * 用户登陆验证拦截器

 * @author AdminTH

 *

 */

public class UserInterceptor extends AbstractInterceptor {

 

// 拦截器业务处理方法.....

@Override

public String intercept(ActionInvocation invocation) throws Exception {

//1. 获取ActionContext

ActionContext ac = invocation.getInvocationContext();

//2. 获取登陆用户

Object obj = ac.getSession().get("userInfo");

//3. 判断

if (obj == null) {

// 没有登陆,不放行

return "input";

else {

// 已经登陆,放行!

return invocation.invoke();

}

}

 

}

 

Struts.xml

 

<struts>

 

<package name="user" extends="struts-default">

<!-- 定义拦截器 -->

<interceptors>

<interceptor name="user" class="cn.itcast.interceptor.UserInterceptor"></interceptor>

<interceptor-stack name="userStack">

<!-- 指定栈中定义的拦截器:先引入默认栈,再引入自定义栈! -->

<interceptor-ref name="defaultStack"></interceptor-ref>

<interceptor-ref name="user"></interceptor-ref>

</interceptor-stack>

</interceptors>

<!-- 全局视图 -->

<global-results>

<result name="input">/login.jsp</result>

</global-results>

 

<!-- 登陆 -->

<action name="login" class="cn.itcast.action.LoginAction" method="login">

<!-- 登陆成功,重定向到列表的action -->

<result name="list" type="redirectAction">user_list.action</result>

</action>

<!-- 用户管理(列表展示、新增、修改等功能 -->

<action name="user_*" class="cn.itcast.action.UserAction" method="{1}">

<!-- 哪个action需要登陆验证,就引入相应的拦截器栈 -->

<interceptor-ref name="userStack"></interceptor-ref>

<result name="list">/WEB-INF/list.jsp</result>

</action>

 

</package>

 

</struts>

 

 

 

总结:

哪个action需要登陆验证,就引入相应的拦截器栈, 比较麻烦!

 

 

 

方式2:  使用全局拦截器引入方式

 

//方式2

@Override

public String intercept(ActionInvocation invocation) throws Exception {

/*

 * 不验证登陆!(或注册!)

 * 思路:

 *  拿到当前执行的方法,如果是“login”, 直接放行!

 *              如果不是"login", 验证

 */

// 获取当前执行的方法名称

String method = invocation.getProxy().getMethod();

// 判断:如果是登陆方法,就放行

if("login".equals(method)) {

return invocation.invoke();

}

//1. 获取ActionContext

ActionContext ac = invocation.getInvocationContext();

//2. 获取登陆用户

Object obj = ac.getSession().get("userInfo");

//3. 判断

if (obj == null) {

// 没有登陆,不放行

return "input";

else {

// 已经登陆,放行!

return invocation.invoke();

}

}





原文地址:https://www.cnblogs.com/dantefung/p/4830568.html