Struts2入门及基本概念

Struts2

1、基本概念

1.1、掌握Struts 2的执行过程

使用Struts 2 开发程序的基本步骤

  1. 加载Struts 2 类库
  2. 配置web.xml文件
  3. 开发视图层页面
  4. 开发控制层Action
  5. 配置struts.xml文件
  6. 部署、运行项目

1.1.1、加载Struts2 类库

文件名说 明
struts2-core-xxx.jar Struts 2框架的核心类库
xwork-core-xxx.jarXWork类库Struts 2的构建基础
ognl-xxx.jarStruts 2使用的一种表达式语言类库
freemarker-xxx.jarStruts 2的标签模板使用类库
javassist-xxx.GA.jar对字节码进行处理
commons-fileupload-xxx.jar文件上传时需要使用
commons-io-xxx.jarJava IO扩展
commons-lang-xxx.jar包含了一些数据类型的工具类

可以在idea工具里直接点出来
在这里插入图片描述

配置pom.xml文件(加载类库)

  <dependencies>
    <dependency>
      <groupId>org.apache.struts</groupId>
      <artifactId>struts2-core</artifactId>
      <version>2.5.22</version>
    </dependency>
    <dependency>
      <groupId>ognl</groupId>
      <artifactId>ognl</artifactId>
      <version>3.2.26</version>
    </dependency>
    <dependency>
      <groupId>org.freemarker</groupId>
      <artifactId>freemarker</artifactId>
      <version>2.3.30</version>
    </dependency>
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.27.0-GA</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.7</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.11</version>
    </dependency>
  </dependencies>

1.1.2、配置web.xml文件

将全部请求定位到指定的Struts 2过滤器中

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>struts2demo</display-name>

  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.filter.
      StrutsPrepareAndExecuteFilter
    </filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
</web-app>

1.1.3、开发视图层页面

login.jsp登陆页面

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<s:form method="post">
    <p>
        用户名:
        <s:textfield name="user.username"/>
        <s:fielderror fieldName="user.username"/>
    </p>
    <p>
        密 码:
        <s:password name="user.password"/>
        <s:fielderror fieldName="user.password"/>
    </p>
    <p>
        <s:submit value="登录"/>
    </p>
    <p style="color: red"><s:property value="errorMessage"/></p>

</s:form>
</body>
</html>

login_success.jsp登陆成功页面

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录成功</title>
</head>
<body>
<h1>登录成功</h1>
<p>欢迎你:${sessionScope.LoginUser}</p>

<s:if test="#session.LoginUser==null">没有登录</s:if>
<s:else>已登录</s:else>
<hr>
<s:iterator value="userList">
    <s:property value="username"/>
    <s:property value="password"/>
    <br>
</s:iterator>
</body>
</html>

1.1.4、开发控制层Action

package cn.st.struts2demo.action;

import cn.st.struts2demo.entity.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

import java.util.ArrayList;
import java.util.List;

public class LoginAction extends ActionSupport {

    private User user;
    private String errorMessage;
    private List<User> userList = new ArrayList<>();

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }


    @Override
    public void validate() {
        if (user != null){
            if ("".equals(this.user.getUsername())){
                addFieldError("user.username","用户名不能为空");
            }
            if ("".equals(this.user.getPassword())){
                addFieldError("user.password","密码不能为空");
            }
        }
    }

    //此处的名字不叫excute()方法,所以配置struts文件里要加上method属性
    public String login(){
        if (null == this.user){
            return INPUT;
        }
        if (this.user.getUsername().equals("admin") && this.user.getPassword().equals("123")){
          //把当前登陆的信息存到session里

            ActionContext.getContext().getSession().put("LoginUser",this.user.getUsername());
            return SUCCESS;
        }
        //返回error之前,提示错误消息
        this.errorMessage="用户名或者密码错误";
        return ERROR;
    }

    //希望登陆成功后重定向,地址栏不再显示login,还要去struts文件配置
    public String loginSuccess(){
        userList.add(new User("aaa","1234576"));
        userList.add(new User("bbb","123412"));
        return SUCCESS;
    }
}

1.1.5、配置struts.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
	<!--配置URL的扩展名,现在为没有后缀-->
	<constant name="struts.action.extension" value=","/>
	<!--表示为简单标签,不要自动生成table等熟悉-->
	<constant name="struts.ui.theme" value="simple"/>
	<!--解决中文乱码问题-->
	<constant name="struts.i18n.encoding" value="UTF-8"/>
	<!--name的名字随意,如xxx;struts-default这个包有很多拦截器;namespace是访问的URL的前缀-->
	<package name="default" extends="struts-default" namespace="/">

		<!--默认打开的的配置-->
		<default-action-ref name="login"/>

		<action name="hello" class="cn.st.struts2demo.action.HelloAction">
			<!--这里就是action类返回的xxx,然后返回welcome页面-->
			<result name="input">/welcome.jsp</result>
			<result name="success">/welcome.jsp</result>
		</action>

		<!--method表示的是action类里方法名-->
		<action name="login" class="cn.st.struts2demo.action.LoginAction" method="login">
			<result name="input" >/login.jsp</result>
			<!--跳转到loginSuccess,且改下类型,默认类型为dispacher(转发)redirect(后面要加url-->
			<result name="success" type="redirectAction">loginSuccess</result>
			<!--<result name="success" type="redirect">/loginSuccess</result>-->
			<result name="error">/login.jsp</result>
		</action>

		<!--重定向-->
		<action name="loginSuccess" class="cn.st.struts2demo.action.LoginAction" method="loginSuccess">
			<result name="success">/login_success.jsp</result>
		</action>
	</package>
</struts>
typeresult
dispacher/login.jsp
redirect/loginSuccess
redirectActionloginSuccess

运行部署结果

在这里插入图片描述

1.2、Struts 2访问Servlet API

登录成功,如何使用session保存用户信息?

解耦(推荐)从ActionContext中获取session,以key/value形式保存数据
耦合获取session,以setAttribute()的方式保存数据

1.2.1、与Servlet API解耦的访问方式

对Servlet API进行封装

  • 提供了三个Map对象访问request、session、application作用域

通过ActionContext类获取这三个Map对象

  • Object get(“request”)
  • Map getSession()
  • Map getApplication()
  ActionContext.getContext().getSession().put("LoginUser", this.user.getUsername());

1.2.2、与Servlet API耦合的访问方式

通过ServletActionContext类获取Servlet API对象

  • ServletContext getServletContext()
  • HttpServletResponse getResponse()
  • HttpServletRequest getRequest()

通过request.getSession()获取session对象

  • 通过xxx.setAttribute()和xxx.getAttribute() 方法在不同的页面或Action中传递数据
ServletActionContext.getRequest().getSession().setAttribute("LoginUser", this.username);

需要在pom.xml配置文件中把jar包加进来

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>

1.3、能够使用Struts 2实现数据校验

  • 服务器端验证
  • 客户端验证
  • 表单验证功能

Struts 2提供了数据验证机制

  • Action控制类继承ActionSupport类来完成Action开发
  • ActionSupport类不仅对Action接口进行简单实现,同时增加了验证、本地化等支持

重写ActionSupport的validate()方法

@Override
    public void validate() {
        if(user != null) {
            if ("".equals(this.user.getUsername())) {
                addFieldError("user.username", "用户名不能为空");
            }
            if ("".equals(this.user.getPassword())) {
                addFieldError("user.password", "密码不能为空");
            }
        }
    }

表单提交过来,会先去验证validate方法,如果调用了addFieldError()这种方法,添加了错误的消失,就不会去调用action方法,而是直接去调用input方法

在jsp页面,s是struts定义的标签库

<%@ taglib prefix="s" uri="/struts-tags" %>
  <s:fielderror fieldName="user.password"/>

1.4、掌握Struts 2框架的标签使用

1.4.1、常用表单标签

标 签说 明
<s:form>…</s:form>表单标签
<s:textfield>…</s: textfield>文本输入框
<s:password>…</s: password>密码输入框
<s:textarea>…</s: textarea>文本域输入框
<s:radio>…</s: radio>单选按钮
<s:checkbox>…</s: checkbox>多选框
<s:submit/>提交标签
<s:reset/>重置标签
<s:hidden/>隐藏域标签

1.4.2、常用非表单标签

标 签说 明
<s:actionerror/>显示Action错误
<s:actionmessage/>显示Action消息
<s:fielderror/>显示字段错误

1.4.3、常用通用标签

名称标 签说 明
条件标签<s:if>……</s:if>根据表达式的值,判断将要执行的内容
条件标签<s:elseif>……</s:elseif>根据表达式的值,判断将要执行的内容
条件标签<s:else>……</s:else>根据表达式的值,判断将要执行的内容
迭代<s:iterator>……</s:iterator>用于遍历集合

2、Struts 2配置详解

2.1、掌握Struts 2的基本架构

Login.jsp页面——>核心控制器——>Action——>Result——>manager.jsp页面

2.1.1、核心控制器

需要在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>

2.1.2、Action

创建Action

  • 实现Action接口
  • 继承ActionSupport类(建议)

配置Action

<struts>
	<package name="default" namespace="/" extends="struts-default">
	<!--name里面相当于一个URL-->
		<action name="login" class="cn.houserent.action.LoginAction">
			<result name="success">/page/manage.jsp</result>
			<result name="input">/page/login.jsp</result>						       
			<result name="error">/page/error.jsp</result>
		</action>
	</package>
</struts>

Action的作用

  • 封装工作单元
  • 数据转移的场所
  • 返回结果字符串

示例

public class HelloWorldAction implements Action {	
	  private String name = "";
	  private String message = "";	
	  public String execute() {
		  this.setMessage("Hello,"+this.getName()+"!");
		  return SUCCESS;
	  }
	  //...省略setter/getter方法 
}
2.1.2.1、method属性
  • 实现Action中不同方法的调用
  • 特点:避免动态方法调用的安全隐患、导致大量的Action配置
<action name="login" 
	  class="cn.houserent.action.UserAction" method="login">
	……
</action>
<action name="register" 
	class="cn.houserent.action.UserAction" method="register">
	 ……
</action>
1、 动态方法调用(调用有安全隐患)

作用:减少Action数量
使用:actionName!methodName.action
禁用:将常量struts.enable.DynamicMethodInvocation设置为false

在struts.xml文件

<!--动态调用方法-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>

但是这里只允许调用全局里允许的方法
在struts-dafault.xml(这里是系统文件不允许修改)

   <global-allowed-methods>execute,input,back,cancel,browse,save,delete,list,index</global-allowed-methods>

所以可以在struts.xml文件的package里添加

<!--.在正则表达式表示一个任意值,*表示任意值-->
<global-allowed-methods>regex:.*</global-allowed-methods>

新建一个方法

  1. 可在配置文件了再添加一个action
  2. 配置动态绑定访问,直接用!方法名调用
	<action name="hello" class="cn.bdqn.struts2demo.action.HelloAction">
			<result name="input">/welcome.jsp</result>
			<result name="success">/welcome.jsp</result>
			<result name="error">/welcome_success.jsp</result>
		</action>

调用hello里的方法haha
http://localhost:8080/struts2demo2_war_exploded/hello!haha

2、通配符(*)

另一种形式的动态方法调用,比动态方法安全,且
{1}都表示*

	<action name="*Hello" class="cn.bdqn.struts2demo.action.HelloAction" method="{1}">
			<result name="input">/welcome.jsp</result>
			<result name="success">/{1}_success.jsp</result>
		</action>

访问http://localhost:8080/struts2demo2_war_exploded/executeHello
注:两个*不能连在一起,可以*_*Hallo这样命名

且与把动态方法的配置改为false无关<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

2.1.3、Result

实现对结果的调用
result元素的值指定对应的实际资源位置
name属性表示result逻辑名

<struts>
	<package name="default" namespace="/" extends="struts-default">
		<action name="login" class="cn.houserent.action.LoginAction">
			<result name="success">/page/manage.jsp</result>
			<result name="input">/page/login.jsp</result>								
			<result name="error">/page/error.jsp</result>
		</action>
	</package>
</struts>

优点:减少了action的数量,还比较安全
在这里插入图片描述

置默认Action

没有Action匹配请求时,默认Action将被执行
通过<default-action-ref … />元素配置默认Action
1、配置default属性,2、配置defaultAction的action

<struts>
  	<default-action-ref name="defaultAction"/ >
	<package name="default" extends="struts-default">
		<action name="defaultAction">
			<result>error.jsp</result>			
		</action>
	</package>
</struts>

2.2、 struts.xml(命名固定)

核心配置文件,主要负责管理Action
通常放在WEB-INF/classes(项目编译之后才有class,可在target里找到)目录下,在该目录下的struts.xml文件可以被自动加载
可有若干个constant常量

<struts>
  	<constant name="" value=""/>
	<package name="" namespace="" extends="">
		<action name="" class="">
			<result name=""></result>			
		</action>
	</package>
</struts>

2.2.1、constant元素

配置常量,可以改变Struts 2框架的一些行为
name属性表示常量名称,value属性表示常量值

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

产生table的标签,simple是不产生任何标签

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

2.2.2、package元素

  • 包的作用:简化维护工作,提高重用性
  • 包可以“继承”已定义的包,并可以添加自己包的配置(除非有重要原因,自定义的包应该总是扩展struts-default包)
  • name属性为必需的且唯一,用于指定包的名称
  • extends属性指定要扩展的包
  • namespace属性定义该包中action的命名空间 ,可选
<struts>
  	<constant name="" value=""/>
	<package name="default" namespace="/" extends="struts-default">
		<action name="" class="">
			<result name=""></result>			
		</action>
	</package>
</struts>

struts-default.xml

Struts 2默认配置文件,会自动加载
struts-default包在struts-default.xml文件中定义

struts-plugin.xml

Struts 2插件使用的配置文件
加载顺序:struts-default.xml ——struts-plugin.xml ——struts.xml

常用结果类型

dispatcher类型默认结果类型,后台使用RequestDispatcher转发请求
redirect类型后台使用的sendRedirect()将请求重定向至指定的URL
redirectAction类型主要用于重定向到Action
<result name="success" type="redirectAction">loginSuccess</result>

动态结果

配置时不知道执行后的结果是哪一个,运行时才知道哪个结果作为视图显示给用户

  this.result="loginSuccess";
<result name="success" type="redirectAction">${result}</result>

可以只配置一个result,但是可以跳转到不同界面
注意type的不同,地址赋值也不一样

全局结果

实现同一个包中多个action共享一个结果

<struts>	
	<default-action-ref name="defaultAction"/ >
	<package name="default" extends="struts-default">
		<global-results>
			<result name="error">/page/error.jsp</result>
			<result name="login" type="redirect">/page/login.jsp</result>
		</global-results>	
			//注意package的配置
		…省略action的配置…
	</package>
</struts>

但是这个全局只在当前package里可用

掌握Struts 2中文乱码的解决?

3、OGNL

3.1、什么是OGNL

  • Object Graph Navigation Language
  • 开源项目,取代页面中Java脚本,简化数据访问
  • 和EL同属于表达式语言,但功能更为强大

3.2、OGNL在Struts 2中做的两件事情

  • 表达式语言:将表单或Struts 2标签与特定的Java数据绑定起来,用来将数据移入、移出框架
  • 类型转换 :数据进入和流出框架,在页面数据的字符串类型和Java数据类型之间进行转换
  • OGNL在框架中的作用:数据流入、数据流出

3.3、值栈和OGNL

值栈(ValueStack)

  • 由Struts 2框架创建的存储区域,具有栈的特点
  • Action的实例会被存放到值栈中

OGNL访问值栈

  • 按照从上到下的顺序
  • 靠近栈顶的同名属性会被读取

3.4、类型转换

  • 在基于HTTP协议的Web应用中
    • 客户端请求的所有内容都以文本编码方式传输到服务器端
    • 服务器端的编程语言却有着丰富的数据类型
  • Servlet中,类型转换工作由开发者自己完成
    • int age = Integer.parseInt(agestr);

3.4.1、内置类型转换器

Struts 2提供了多种内置类型转换器,自动对客户端传来的数据进行类型转换

内置类型转换器说 明
String将int、long、double、boolean、String类型的数组或者java.util.Date类型转换为字符串
boolean/Boolean在字符串和布尔值之间进行转换
char/Character在字符串和字符之间进行转换
int/Integer、float/Float、long/Long、double/Double在字符串和数值型数据之间进行转换
Date在字符串和日期类型之间进行转换。具体输入输出格式与当前的Locale相关
数组和集合在字符串数组和数组对象、集合对象间进行转换
3.4.1.1、原始类型和包装类型

内置的日期数据转换
1、创建实体类

package cn.bdqn.struts2demo.entity;
import java.util.Date;
public class User {
    private String username;
    private String password;
    private String age;
    private Date birthday;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public Date getBirthday() { return birthday; }

    public void setBirthday(Date birthday) { this.birthday = birthday; }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

2、register.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户注册</title>
</head>
<body>
<h2>用户注册</h2>
<s:form method="post">
    <p>
        用户名:
        <s:textfield name="user.username"/>
        <s:fielderror fieldName="user.username"/>
    </p>
    <p>
        密 码:
        <s:password name="user.password"/>
        <s:fielderror fieldName="user.password"/>
    </p>
    <p>
        年龄:
        <s:textfield name="user.age"/>
        <s:fielderror fieldName="user.age"/>
    </p>
    <p>
        生日:
        <s:textfield name="user.birthday"/>
        <s:fielderror fieldName="user.age"/>
    </p>
    <p>
        <s:submit value="注册"/>
    </p>
    <p style="color: red"><s:property value="errorMessage"/></p>

</s:form>
</body>
</html>

3、register_success.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册成功</title>
</head>
<body>
<p>用户名:<s:property value="user.username"/></p>
<p>密码:<s:property value="user.password"/></p>
<p>年龄:<s:property value="user.age"/></p>
<p>生日:<s:property value="user.birthday"/></p>
</body>
</html>

5、RegisterAction.java

package cn.bdqn.struts2demo.action;
import cn.bdqn.struts2demo.entity.User;
import com.opensymphony.xwork2.ActionSupport;

public class RegisterAction extends ActionSupport {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String register(){
        if (null==user){
            return INPUT;
        }

        return SUCCESS;
    }
}

6、struts.xml配置action

	<action name="register" class="cn.bdqn.struts2demo.action.RegisterAction" method="register">
			<result name="input">/register.jsp</result>
			<result name="success">/register_success.jsp</result>
		</action>

在这里插入图片描述
在这里插入图片描述

3.4.1.2、自定义类型转换器

新建一个包converter,再新建一个类Dateconverter继承StrutsTypeConverter

package cn.bdqn.struts2demo.converter;

import org.apache.struts2.util.StrutsTypeConverter;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class Dateconverter extends StrutsTypeConverter {
    @Override
    public Object convertFromString(Map map, String[] strings, Class aClass) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
       try {
           date = sdf.parse(strings[0]);
       }catch (Exception e){
           e.printStackTrace();
       }
        return date;
    }

    @Override
    public String convertToString(Map map, Object o) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = (Date)o;
        return sdf.format(date);
    }
}

在资源文件夹新建xwork-conversion.properties文件(应用于全局范围的类型转换器)

java.util.Date=cn.bdqn.struts2demo.converter.Dateconverter

部署运行:此处会发现生日里的年份的格式是2012,而不是默认的12
在这里插入图片描述

自定义多种类型转换

package cn.bdqn.struts2demo.converter;

import org.apache.struts2.util.StrutsTypeConverter;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class Dateconverter extends StrutsTypeConverter {

    private SimpleDateFormat[] sdfs = {
            new SimpleDateFormat("yyyy-MM-dd"),
            new SimpleDateFormat("yyyy年MM月dd日"),
            new SimpleDateFormat("yyyy/MM/dd"),
            new SimpleDateFormat("yyyy.MM.dd")
    };


    @Override
    public Object convertFromString(Map map, String[] strings, Class aClass) {
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Date date = null;

           for (SimpleDateFormat sdf:sdfs) {
               try {
                   date = sdf.parse(strings[0]);
                   break;


               } catch (Exception e) {
                   continue;
               }
           }
        return date;
    }

    @Override
    public String convertToString(Map map, Object o) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = (Date)o;
        return sdf.format(date);
    }
}

3.4.1.3、多值类型数据处理(数组和集合)
  1. 在registerAction.java类里添加数组
private String[] hobbies;
    public String[] getHobbies() {
        return hobbies;
    }

   public void setHobbies(String[] hobbies) {
        this.hobbies = hobbies;
   }
  1. 在registerAction.java类里添加集合
private List<String> hobbies;
    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

在register.jsp里添加多选

    <p>
        爱好:
        <s:checkbox name="hobbies" fieldValue="sport"/>运动
        <s:checkbox name="hobbies" fieldValue="music"/>音乐
        <s:checkbox name="hobbies" fieldValue="game"/>游戏
        <s:checkbox name="hobbies" fieldValue="reading"/>读书
    </p>

在register_success.jsp里添加迭代

<p>
    <s:iterator value="hobbies">
        <s:property /> &nbsp;
    </s:iterator>
</p>

在这里插入图片描述

3.4.1.4、处理类型转换错误
1、向用户输出类型转换错误的前提条件
  • 启动StrutsConversionErrorInterceptor拦截器:拦截器已经包含在defaultStack拦截器栈中
  • Action要继承ActionSupport类 :实质是实现ValidationAware接口
  • 配置input结果映射:页面使用Struts 2表单标签或<s:fielderror>标签
    • Struts 2表单标签内嵌了输出错误信息功能
    • 普通HTML标签需使用<s:fielderror>标签输出转换错误
    <p>
        用户名:
        <s:textfield name="user.username"/>
        <s:fielderror fieldName="user.username"/>
    </p>
2、修改所有类型的转换错误信息

思路:修改xwork.default.invalid.fieldvalue键的值

  • 在struts.xml中指定资源文件的基名<constant name="struts.custom.i18n.resources" value="message"/>
  • 在src目录下创建资源文件message.properties并修改键值xwork.default.invalid.fieldvalue=字段“{0}”的值无效
    struts.xml中的value的值对应src下的资源文件的名字
3、定制特定字段的类型转换错误信息

思路:在Action范围的资源文件中添加I18N消息键invalid.fieldvalue.xxx
在Action包下创建RegisterAction.properties,指定键值invalid.fieldvalue.birthday=生日转换错误

3.5、OGNL表达式注意事项

访问Bean的属性

  • Bean的类型必须遵循JavaBean规范:必须具有无参构造
  • setter/getter方法符合JavaBean规范
public class Address { // 家庭地址
	private String country; // 国家
	private String city; // 城市
	private String street; // 街道
	...  //省略各个属性的setter和getter方法
}

public class User { //用户类
	private String name; //姓名
	private int age;     //年龄
	private Address address; //家庭地址
	...  //省略各个属性的setter和getter方法
}

User对象作为Action的属性,其键名为user

  • 访问name属性 user.name
  • 访问country属性user.address.country

3.5.1、访问集合对象

  • 可以使用属性名[index]的方式访问:列表、数组
  • 可以使用属性名[key]的方式访问:Map对象
  • 使用size或者length获取集合长度
访问列表、数组?

3.6、访问非值栈对象

在这里插入图片描述

<s:set var="list" value="{'aaa','bbb','scc'}" />
<%--这里不是action的属性,就是非值栈,所以要用#--%>
<p><s:property value="#list.size"/></p>
<s:iterator value="#list" >
    <s:property/>,
</s:iterator>

在这里插入图片描述

查看ActionContext中的数据

使用<s:debug/>查看数据
ActionContext的组成

  • 值栈-ValueStack
  • 非值栈-Stack Context

在register_success.jsp页面加上
在这里插入图片描述
在struts.xml中添加,默认是false

<!--开发模式,可以调试-->
	<constant name="struts.devMode" value="true"/>

在这里插入图片描述
可以在debug里面看到很多信息

4、拦截器

掌握Struts 2架构

在这里插入图片描述
HTTPServletRequest——ActionContextCleanUp(清空action的内容)——Other fiters(自己定义的用户编码过滤器、权限过滤器等等)——FilterDispatcher(前端控制器的过滤器)——ActionMapper(建了一个映射表,对应URL要用哪个action处理)——FilterDispatcher——ActionProxy(代理action,会读取struts.xml配置文件)——ConfigurationManager——ActionProxy——ActionInvocation———在执行action之前会经过——系列的过滤拦截器interceptor1到3——Action处理得到结果——result(字符串,根据字符串转发到哪个页面)——Template——321——HTTPServletResponse——客户端
在这里插入图片描述
来和去都要进过拦截器

掌握Struts 2拦截器

Struts 2核心接口和类

名称作用
ActionMapper根据请求的URI查找是否存在对应Action调用
ActionMapping保存调用Action的映射信息,如namespace、name等
ActionProxy在XWork和真正的Action之间充当代理
ActionInvocation表示Action的执行状态,保存拦截器、Action实例
Interceptor在请求处理之前或者之后执行的Struts 2组件

什么是拦截器

  • truts 2大多数核心功能是通过拦截器实现的,每个拦截器完成某项功能
  • 拦截器方法在Action执行之前和之后执行
  • 拦截器栈
    • 从结构上看,拦截器栈相当于多个拦截器的组合
    • 在功能上看,拦截器栈也是拦截器
    • 拦截器与过滤器原理很相似
  • 三阶段执行周期:
    1、做一些Action执行前的预处理
    2、将控制交给后续拦截器或返回
    结果字符串
    3、做一些Action执行后的处理

Action提供附加功能时,无需修改Action代码,使用拦截器来提供

示例

继承父类AbstractInterceptor
关键代码String result = invocation.invoke();

实现接口继承父类(推荐)
implements Interceptorextends AbstractInterceptor
import com.opensymphony.xwork2.interceptor.Interceptor;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

新建一个文件夹interceptor,新建一个类MyTimewInterceptor继承AbstractInterceptor

package cn.bdqn.struts2demo.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyTimewInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {

        //预处理工作
        long startTime = System.currentTimeMillis();
        //执行后续拦截器或action
        String result = actionInvocation.invoke();
        //后续处理工作
        long timeSpan = System.currentTimeMillis()-startTime;
        System.out.println("user Time"+timeSpan+"ms");
        //返回结果字符串
        return result;
    }
}

修改配置文件

<package name="default" extends="struts-default" namespace="/">

		<interceptors>
			<interceptor name="myTime" class="cn.bdqn.struts2demo.interceptor.MyTimewInterceptor"/>
		</interceptors>
		<default-action-ref name="login"/>
		<global-results>
			<result name="login">/login.jsp</result>
		</global-results>
		<global-allowed-methods>regex:.*</global-allowed-methods>

		<action name="login" class="cn.bdqn.struts2demo.action.LoginAction" method="login">
			<result name="input">/login.jsp</result>
			<interceptor-ref name="myTime"/>
			<result name="success" type="redirectAction">${result}</result>
			<result name="error">/login.jsp</result>
		</action>
		
	</package>

看进拦截器和出拦截器的时间
在这里插入图片描述

配置多个拦截器

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
	"http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
	<!--配置URL的扩展名,现在为没有后缀-->
	<constant name="struts.action.extension" value=","/>
	<!--表示为简单标签,不要自动生成table等熟悉-->
	<constant name="struts.ui.theme" value="simple"/>
	<!--解决中文乱码问题-->
	<constant name="struts.i18n.encoding" value="UTF-8"/>
	<!--全局错误变量-->
	<!--<constant name="struts.custom.i18n.resources" value="message"/>-->
	<!--name的名字随意,如xxx;struts-default这个包有很多拦截器;namespace是访问的URL的前缀-->
	<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
	<!--开发模式,可以调试-->
	<constant name="struts.devMode" value="true"/>
	<package name="default" extends="struts-default" namespace="/">

		<interceptors>
			<interceptor name="myTime" class="cn.bdqn.struts2demo.interceptor.MyTimewInterceptor"/>
			<!--定义拦截器栈-->
			<interceptor-stack name="myStack">
				<interceptor-ref name="myTime"/>
				<interceptor-ref name="defaultStack"/>
			</interceptor-stack>
		</interceptors>
		<!--引用设置的拦截器栈-->
		<default-interceptor-ref name="myStack"/>
		<default-action-ref name="login"/>
		<global-results>
			<result name="login">/login.jsp</result>
		</global-results>
		<global-allowed-methods>regex:.*</global-allowed-methods>
		<!--<action name="hello" class="cn.bdqn.struts2demo.action.HelloAction">-->
			<!--<result name="input">/welcome.jsp</result>-->
			<!--<result name="success">/welcome.jsp</result>-->
			<!--<result name="error">/welcome_success.jsp</r
			esult>-->
		<!--</action>-->

		<action name="*Hello" class="cn.bdqn.struts2demo.action.HelloAction" method="{1}">
			<result name="input">/welcome.jsp</result>
			<result name="success">/{1}_success.jsp</result>
		</action>

		<action name="login" class="cn.bdqn.struts2demo.action.LoginAction" method="login">
			<result name="input">/login.jsp</result>
			<interceptor-ref name="myTime"/>
			<result name="success" type="redirectAction">${result}</result>
			<result name="error">/login.jsp</result>
		</action>

		<action name="loginSuccess" class="cn.bdqn.struts2demo.action.LoginAction" method="loginSuccess">
			<result name="success">/login_success.jsp</result>
			<!--引用默认的拦截器栈-->
			<interceptor-ref name="defaultStack"/>
		</action>

		<action name="register" class="cn.bdqn.struts2demo.action.RegisterAction" method="register">
			<result name="input">/register.jsp</result>
			<result name="success">/register_success.jsp</result>
		</action>
	</package>
</struts>

struts2自带的拦截器

params拦截器负责将请求参数设置为Action属性
servletConfig拦截器将源于Servlet API的各种对象注入到Action
fileUpload拦截器对文件上传提供支持
exception拦截器捕获异常,并且将异常映射到用户自定义的错误页面
validation拦截器调用验证框架进行数据验证
workflow拦截器调用Action类的validate(),执行数据验证
  1. struts-default.xml中定义一个defaultStack拦截器栈,并将其指定为默认拦截器
  2. 只要在定义包的过程中继承struts-default包,那么defaultStack将是默认的拦截器

自定义拦截器

实现Interceptor接口继承AbstractInterceptor类
void init():初始化拦截器所需资源提供了init()和destroy()方法的空实现
void destroy():释放在init()中分配的资源——
String intercept(ActionInvocation ai) throws Exception——
利用ActionInvocation参数获取Action状态只需要实现intercept方法即可
返回结果码(result)字符串——

权限验证拦截器(判断用户是否登录)

1、编写拦截器,继承AbstractInterceptor类

ublic class AuthorizationInterceptor extends AbstractInterceptor {
	 
	 public String intercept(ActionInvocation invocation) throws Exception{
		  //获取用户会话信息
		  Map session = invocation.getInvocationContext().getSession();
		  User user = (User)session.get("login");
		  if (user == null) {
			  //终止执行,返回登录页面
			  return Action.LOGIN;
		  } else {
			  //继续执行剩余的拦截器和Action
			  return invocation.invoke();
		  }
	  }
}

2、在struts.xml中配置拦截器
这个拦截器包含在默认拦截器内,所以Action中无需再引用权限拦截器

<package name="renthouse" extends="struts-default">
	<interceptors>
		<!--定义权限验证拦截器-->
		<interceptor name="myAuthorization"
			class="cn.houserent.interceptor.AuthorizationInterceptor">
		</interceptor>
		 <!--定义拦截器栈-->
		<interceptor-stack name="myStack">
			<interceptor-ref name="defaultStack"/>
			<interceptor-ref name="myAuthorization"/>
		</interceptor-stack>
	</interceptors>
	<!-- 定义默认拦截器 -->
	<default-interceptor-ref name="myStack"/>
	...略...
</package>

3、在struts.xml中配置拦截器

掌握Struts 2框架的文件上传和下载

Commons-FileUpload组件Commons-FileUpload组件特点
Commons是Apache开放源代码组织的一个Java子项目,其中的FileUpload是用来处理HTTP文件上传的子项目使用简单:可以方便地嵌入到JSP文件中,编写少量代码即可完成文件的上传功能
——能够全程控制上传内容
——能够对上传文件的大小、类型进行控制

文件上传

jar包环境要求

  • commons-fileupload-xxx.jar
  • commons-io-xxx.jar

实现步骤

  • 设置表单提交属性
  • 编写文件上传处理Action
  • 配置Action

文件下载

Spring中Bean的作用域

作用域说 明
singleton 默认值Spring以单例模式创建Bean的实例,即容器中该Bean的实例只有一个
prototype每次从容器中获取Bean时,都会创建一个新的实例
request用于Web应用环境,针对每次HTTP请求都会创建一个实例
session用于Web应用环境,同一个会话共享同一个实例,不同的会话使用不同的实例
global session仅在Portlet的Web应用中使用,同一个全局会话共享一个实例。对于非Portlet环境,等同于session

1、使用Web环境下的作用域,要在web.xml文件中配置RequestContextListener或RequestContextFilter

!-- 指定Bean的作用域为prototype -->
<bean id="userAction" class="cn.houserent.action.UserAction" scope="prototype">

2、在action的类里添加注解

@Scope("prototype")

在这里插入图片描述

回调机制

Spring提供了回调机制

  • 模板固化了不变的、流程化的内容,简化使用
  • 回调允许我们在固化的流程中加入变化的内容

HibernateCallback接口

  • public T execute(HibernateCallback action) throws DataAccessException
public List<Employee> find(final int page, final int size) {
    return this.getHibernateTemplate().execute(
        new HibernateCallback<List<Employee>>() {
            public List<Employee> doInHibernate(Session session)
                        throws HibernateException, SQLException {
                Query query = session.createQuery("from Employee");
                query.setFirstResult((page - 1) * size);
                query.setMaxResults(size);
                return query.list();
            }
        }
    );    
}

当把方法中的局部变量传递给它的内部类使用时,必须把该变量声明为final

5、搭建ssh框架

掌握Spring与Hibernate的集成
掌握Spring与Struts 2的集成
方法一:定义独立的Hibernate配置文件,由Spring导入并创建会话工厂Bean
方法二:在Spring配置文件中进行集中配置
先配置数据源,再以此为基础配置会话工厂Bean
持久化类的映射文件可以逐个配置,也可以按目录导入

以上可以统一变为以下方法
AO类继承HibernateDaoSupport
使用getHibernateTemplate()方法获取HibernateTemplate实例完成持久化操作
创建baseDao.java

package cn.st.houserents.dao;

import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import javax.annotation.Resource;

//继承HibernateDaoSupport可以注入
public class BaseDao extends HibernateDaoSupport {

    @Resource
    public void setSessionFacotry(SessionFactory sessionFactory){//    这里单词ot换了位置
        super.setSessionFactory(sessionFactory);
    }
}

创建需要的dao和daoImpl

编写用户业务接口和实现类service和serviceImpl

Spring与Struts 2集成

Hibernate注解

Spring注解

添加struts2-spring-plugin-xxx.jar
按照名称匹配的原则定义业务Bean和Action中的setter方法
在struts.xml正常配置Action

  1. 采用此种配置方式时,Action的实例由Spring创建,Struts 2插件的工厂类只需根据Action Bean的id查找该组件使用即可
  2. 此种方式可以为Action进行更灵活的配置,但代价是在Spring配置文件中需要定义很多Action Bean,增加了配置工作量,如非必需并非首选
  3. 采用此种配置方式,同样需要添加struts2-spring-plugin-xxx.jar文件

struts2注解

实体类@Entity声明此类是实体类
@Table(name=“数据库表名”)声明此对象映射到数据库的数据表
@Id
@Column(name=“ID”)对应数据库表的列
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值