Java Web笔记(六)

来源:互联网 发布:mac导入照片不清晰 编辑:程序博客网 时间:2024/06/07 08:45

Struts2

MVC的理想及优势

MVC并不是Java语言所特有的设计思想,也并不是Web应用所特有的思想,它是所有面向对象程序设计语言都应该准守的规范。

MVC思想将一个应用分成三个基本部分:Model(模型)View(视图)、和Controller(控制器),这三个部分以最少的耦合协同工作,从而通告应用的可扩展性和维护性。

MVC特点:

1、多个视图可以对应一个模型。可以减少代码的复制及代码的维护量。

2、模型返回的数据与显示逻辑分离。模型数据可以应用任何的显示技术,例如jspVelocity或者直接产生exclepdf等文档

3、控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起,完成不同的请求。因此,控制层可以说是包含了用户请求权限的概念。

4MVC更符合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,有利于通过工程化和工具化产生管理程序代码。

Struts2的作用

主要做业务处理和页面跳转。

Struts2框架结构


Struts2处理流程

1、浏览器发送请求,例如请求http://localhost:8080/struts/user.do

2、核心控制器FilterDispatcher(已过时)根据请求决定调用合适的Action ,新的核心控制器是StrutsPrepareAndExecuteFilter(最新的);

3WebWork的拦截器链自动对请求应用通用功能,例如workflowvalidation或文件上传的功能

4、回调Actionexecute方法,该execute方法先获取用户请求参数,然后执行某种数据库操作,既可以是将数据保存到数据库,也可以从数据库中检索信息。实际上,因为Action只是一个控制器,它会调用业务逻辑组件来处理用户的请求。

5Actionexecute方法处理结果信息将被输出到浏览器中,可以是html页面,图像,也可是是pdf等。

Struts2框架的搭建

Struts2依赖的jar

asm-3.3.jar

asm-commons-3.3.jar

asm-tree-3.3.jar

commons-fileupload-1.3.2.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.3.jar

log4j-core-2.3.jar

ognl-3.0.19.jar

struts2-core-2.3.30.jar

xwork-core-2.3.30.jar

配置struts2的核心控制器

web.xml中配置filter:

<filter>       <filter-name>struts</filter-name>      <!-- 核心控制器 -->       <filter-class>          org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter      </filter-class></filter><filter-mapping>      <filter-name>struts</filter-name>      <!-- 所有struts请求后缀以.aciton结尾(即以.action结尾的请求struts2都拦截) -->      <url-pattern>*.action</url-pattern></filter-mapping>

配置struts2

1)新建struts.xml(文件名不能改变)文件,struts.xml文件的位置要在classpath下,即在src下的目录中即可

2)配置

<?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:    package的名字(自定义的)extends: struts-default,继承struts2框架的默认行为namespace: 命名空间; 如果写了命名空间,那个访问路径的web应用名后面要加上该命名空间,只写一个 / 则不用加--><package name="user" extends="struts-default" namespace="/"><!--配置控制器name:  相当于servlet中的url-patternclass: 相当于servlet中的servlet-class--><action name="user" class="action.UserAction"><result name="login">/WEB-INF/login.jsp</result><result name="regist">/WEB-INF/regist.jsp</result></action></package></struts>

3)编写控制器

控制器要实现Action接口,并重写execute()方法;

也可以不实现Action接口,只需要在类里写一个execute()方法,访问该类时会把该类自动作为Action类。

注意:struts2中的请求方法不能提供任何的参数

package action;import com.opensymphony.xwork2.Action;public class UserAction implements Action {/** * 控制器的入口 */@Overridepublic String execute() throws Exception {return "login";}}

访问地址:http://localhost:8080/struts2/login.action

3)动态调用

配置struts2常量,使其支持动态调用:

<!-- 是否支持动态调用,默认为false(不支持),true(支持) --><constant name="struts.enable.DynamicMethodInvocation" value="true" />

动态调用方式一

actionName!methodName.action

动态调用方式二

struts.xml中的action中配置method属性,指定action请求调用的方法

注意:动态调用中,方法名不能以get开头。

获取页面传递参数

属性驱动

步骤:

     1. action中声明成员属性

     2. 提供对应的settergetter方法

注:页面中的key要与action中的成员属性要保持一致

示例:

Action

public class UserAction { // 这里使用的是动态调用/** * 1. 设置成员属性 */private String userName;private String password;/** * 2. 提供setter和getter方法 */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;}/** * action方法 */public String login() throws Exception {return "login";}public String loginSubmit() throws Exception {System.out.println("用户名:" + userName);System.out.println("密码:" + password);return "login";}}

Jsp页面:

<form action="${pageContext.request.contextPath }/user/login.action">    <label>用户名:</label>    <input type="text" name="userName" /><br/>    <label>密码:</label>    <input type="password" name="password" /><br/>    <input type="submit" /></form>

模型驱动

步骤:

1. 创建实体类

2. action中声明实体的成员变量

3. 提供对应的settergetter方法

注:页面中的key后部分和实体中的属性保持一致,前面部分和控制器中的属性保持一致

示例:

实体类:

public class User {private String userName;private String password;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;}@Overridepublic String toString() {return "User [userName=" + userName + ", password=" + password + "]";}}

Action

public class UserAction2 {/** * 2. 声明成员属性 */private User user;/** * 3. 提供对应的setter和getter方法 * @return */public User getUser() {return user;}public void setUser(User user) {this.user = user;}/** * action方法 */public String login() {System.out.println(user);return "login";}}

Jsp页面:

<form action="${pageContext.request.contextPath }/user/login.action">    <label>用户名:</label>    <input type="text" name="user.userName" /><br/>    <label>密码:</label>    <input type="password" name="user.password" /><br/>    <input type="submit" /></form>

模型驱动(实现ModelDriven接口)

步骤:

    1. 创建实体类

    2. action中声明成员属性

    3. 实现ModelDriven接口

    4. 重写getModel()方法

注意:

    1. 不需要提供gettersetter方法

    2. 该模型驱动不会自动帮我们创建模型对象,要在getModel()方法中判断模型对象是否为空,为空则new一个模型对象,只有创建完对象并实例化后才能接收参数

示例:

实体类同上;

Action

public class UserAction3 implements ModelDriven<User> { // 3. 实现ModelDriven接口/** * 2. 声明成员属性 */private User user;/** * 控制器的入口 */public String login() {System.out.println(user);return "login";}/** * 4. 重写getModel()方法(固定写法) */@Overridepublic User getModel() {if(user == null) {user = new User();}return user;}}

Jsp页面:

<form action="${pageContext.request.contextPath }/user/login.action">    <label>用户名:</label>    <input type="text" name="userName" /><br/>    <label>密码:</label>    <input type="password" name="password" /><br/>    <input type="submit" /></form>

模型驱动(【优化】实现ModelDriven接口)

步骤:

    1. 编写控制器基类

    2. 继承控制器基类

编写控制器基类:

import java.lang.reflect.ParameterizedType;import com.opensymphony.xwork2.ModelDriven;public class BaseAction<T> implements ModelDriven<T> { // 1. 继承ModelDriven接口/** * 2. 声明泛型成员变量 */private T t;/** * 3. 重写getModel()方法 */@Overridepublic T getModel() {if(t == null) {// 获取泛型代表的真正的类ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();// 获取真实类型的类对象Class<T> clz = (Class<T>)type.getActualTypeArguments()[0];// 通过类对象获取对象try {t = clz.newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return t;}}

控制器继承控制器基类:

public class UserAction3_2 extends BaseAction<User> { // 实现ModelDriven接口/** * 控制器的入口 */public String login() {System.out.println(this.getModel());return "login";}}

基于servlet API接收页面参数

步骤:

    直接在获取参数的地方编写原生的代码。

Action

public class UserAction4  {/** * 控制器的入口 */public String login() {// 获取requestHttpServletRequest request = ServletActionContext.getRequest();// 接收页面参数String userName = request.getParameter("userName");String password = request.getParameter("password");System.out.println(userName);System.out.println(password);return "login";}}

Jsp页面:

<form action="${pageContext.request.contextPath }/user/login.action" method="post">    <label>用户名:</label>    <input type="text" name="userName" /><br/>    <label>密码:</label>    <input type="password" name="password" /><br/>    <input type="submit" /></form>

基于struts API接收页面参数

步骤:

    接在获取参数的地方编写原生的代码。

Action

public class UserAction5 {/** * 控制器的入口 */public String login() {Map<String, Object> parameters = ActionContext.getContext().getParameters(); // Object是一个数组String[] userName = (String[]) parameters.get("userName");String[] password = (String[]) parameters.get("password");System.out.println(userName[0]);System.out.println(password[0]);return "login";}}

Jsp页面:

<form action="${pageContext.request.contextPath }/user/login.action" method="post">    <label>用户名:</label>    <input type="text" name="userName" /><br/>    <label>密码:</label>    <input type="password" name="password" /><br/>    <input type="submit" /></form>

Struts2的基本配置

Struts2常量配置

1. struts2中的常量在struts-core-x.x.jar/org.apache.struts2/default.properties配置文件中。

2. struts常量既可以在struts.xml文件中配置,也可以在struts.properties文件中配置。推荐在struts.xml中配置,保留在properties文件中配置是为了WebWork的向后兼容。

3. 常用的常量:

    struts.i18n.encoding:指定WEB应用的默认编码集,支持中文,可以配置GBKUTF-8

    struts.devMode:是否使用开发模式,如果为true,在程序出现异常的时候,出现更多的错误信息;

    struts.enable.DynamicMethodInvocation:是否支持动态方法调用;

    struts.action.extension:指定struts的请求后缀,默认值为action指定多个后缀,用逗号分隔;

    struts.multipart.saveDir:指定上传文件保存的临时路径;

    struts.multipart.maxSize:指定上传文件的最大字节数;

4. struts配置文件中引入常量的方式:

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

注:name是常量名,value是常量值;

5. 去除struts2的请求后缀

  修改web.xml的核心控制器的url-pattern,改为/*

注:只支持不写.action和写.action,其它形式不支持,这是因为struts的后缀常量在起作用。默认后缀常量为struts.action.extension=action,,

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>

修改struts后缀常量:

    在struts.xml中配置下面代码:

<constant name="struts.action.extension" value=",," /><!-- 后面不用写后缀 -->

命名空间

    考虑到web应用中需要同名的ActionStruts2通过命名空间的方式来管理Action,同一个命名空间里不能有同名的action,不同的命名空间可以有同名action

struts2不支持为单独的action指定namespace,而是通过package来指定。如果包没有指定namespace,默认 namespache""

    访问时,要在web应用名后面跟上命名空间名。

示例:

<package name="app" extends="struts-default" namespace="/app"><action name="login" class="com.struts.action.Login"><result name="success">/WEB-INF/list.jsp</result><result name="input">/WEB-INF/login.jsp</result><result name="error">/WEB-INF/error.jsp</result></action></package>

访问地址:http://localhost:8080/struts/app/login.action

Actionmethod属性

如果在配置Action的时候,指定method属性,则可以让action调用指定的方法,而不再必须通过execute()方法来处理用户的请求。

<package name="default" extends="struts-default" namespace="/">    <!--默认会调用login方法--><action name="app" class="com.struts.action.Login" method="login"><result name="success">/WEB-INF/list.jsp</result><result name="input">/WEB-INF/login.jsp</result><result name="error">/WEB-INF/error.jsp</result></action></package>

访问地址:http://localhost:8080/struts/app.action  自动调用actionlogin方法;

使用通配符配置action

注:通配符和表达式一起使用。

action标签中,name属性值支持通配符;Action标签的class属性和method属性、result标签体这三个位置支持表达式。

{1}1表示第1个星号

示例一:

<package name="user" extends="struts-default" namespace="/user"><action name="*" class="action.UserAction3_2" method="{1}"><result name="login">/WEB-INF/login3.jsp</result></action></package>

访问地址:http://localhost:8080/day0719_struts2/user/login

示例二:

<package name="user" extends="struts-default" namespace="/user"><action name="*_*" class="action.{1}Action3_2" method="{2}"><result name="login">/WEB-INF/{2}3.jsp</result></action></package>

访问地址:http://localhost:8080/day0719_struts2/user/User_login

Struts2模块开发

引入项目模块struts-xxx.xml配置文件

<!-- 引入相关模块的配置文件 -->

<include file="struts-xxx.xml" />

示例:

struts-user.xml模块配置文件

<?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" extends="struts-default" namespace="/user"><action name="*" class="com.soft863.action.UserAction"><result name="success">/WEB-INF/pages/{1}.jsp</result></action></package></struts>

struts.xml配置文件中引入模块配置文件:

<!-- 引入相关模块的配置文件 --><include file="struts-user.xml" />

Struts2后台往前台传参

使用ServletAPI

ServletActionContext.getRequest().setAttribute(key, value);

使用StrutsAPI

ActionContext.getContext.getContext().put(key, value);

Struts2中的跳转方式

struts2中的跳转方式也是分为转发(forward)和重定向(sendRedirect)。

struts2中默认的跳转方式是转发(forward)。

struts2的跳转方式从大方面上分为转发和重定向,细分为:dispatcherchainredirectredirectActionstreamjsonplainText。(标红为重点掌握)

配置方式:在result标签中的type属性配置

struts2的结果类型需要实现com.opensymphony.xwork2.Result接口,这个结果是所有Action执行结果的所有接口。如果需要实现自己的返回类型,需要实现该接口。并且在struts.xml配置。

struts2默认支持的结果类型有:(标红为重点掌握)

dispatcherorg.apache.struts2.dispatcher.ServletDispatcherResult默认类型)用于jsp整合类型(转发:用于跳转到jsp页面)

chaincom.opensymphony.xwork2.ActionChainResult   链式处理结果类型(转发:用于跳转到Action

redirectorg.apache.struts2.dispatcher.ServletRedirectResult用于直接跳转到其他url的类型(重定向:用于跳转到jsp页面)

redirectActionorg.apache.struts2.dispatcher.ServletActionRedirectResult  跳转到其他action的类型(重定向:用于跳转到Action

streamorg.apache.struts2.dispatcher.StreamResult向浏览器返回一个InputStream(一般用于下载)

json: json格式返回数据

plainTextorg.apache.struts2.dispatcher.PlainTextResult用于显示原始代码的结果类型

全局结果映射

package中定义全局结果映射,对所有的Action都有效。

注意:action指定了同样的结果类型的时候,会优先使用action中配置的映射关系。覆盖全局结果映射

<global-results><result name="error">/error.jsp</result></global-results>

示例:

<package name="default" extends="struts-default" namespace="/"><!-- 全局结果映射(在当前package下,对所有的Action都有作用) --><global-results><result name="error">/WEB-INF/error.jsp</result></global-results><action name="*" class="com.soft863.action.DefaultAction"><result name="success">/WEB-INF/pages/{1}.jsp</result><!--当action中配置时,会覆盖掉全局的-->           <result name=”error”>/WEB-INF/pages/error.jsp</error></action></package>

异常处理

所有成熟的MVC框架,都应该对异常的处理给出成熟的异常处理机制。

struts2提供了一种声明式异常处理。

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

通过result属性指定映射的名字,转入result结果,exception指定异常类型;

说明:当发生java.lang.Exception时,会转到result=”error”对应的视图。

配置全局异常处理:

<global-exception-mappings><exception-mapping result="error" exception="java.lang.Exception"></exception-mapping></global-exception-mappings>

也可以配置局部的,局部是在action标签中配置,但action中定义的会覆盖掉全局中配置的。

Struts中的值栈和栈

Struts将参数放在了两个位置:值栈和栈;

    值栈:参访Action和模型,模型位于栈顶;

    栈:存放非Action和模型外的其他数据;

访问值栈和栈中的数据:

    值栈:使用${key }

    通过ActionContext.getContext.put(key, value)存放的值,这种方式存放值是存放在栈中,也可以通过${key }获取。

    注:如果ActionContext.getContext.put存放的key,与值栈中同名,默认先从值栈中取值。

Jstlc:url标签

<c:url value=”” />或者<c:url value=””></c:url>  获取项目根路径,value中填写资源路径

<%@ taglib uri="/struts-tags" prefix="s"%>

相当于${pageContext.request.contextPath},后面跟具体资源的路径

示例:

<c:url value="/user/regist" />

WEB-INF

WEB-INF下的资源是受保护的资源,只能通过forword(转发)形式跳转访问。

forword跳转分两种情况:

    1 跳转到一个要显示的页面的请求;

    2 带参跳转到一个要显示的页面的请求;

Struts2标签

导入struts2标签

<%@ taglib uri="/struts-tags" prefix="s"%>

struts2标签

<s:debug></s:debug>

Struts2高级特性

Struts2注册转换器(了解)

局部类型转换器的文件名格式为:ActionClassName-conversion.properties

全局类型转换器的文件名格式为:xwork-conversion.properties

注意:该配置文件和ActionClassName存放在一个位置。

Struts2拦截器

    对于struts2的拦截器体系而言,当我们需要使用某个拦截器时,只需要在配置文件中应用拦截器即可;如果不需要使用该拦截器,也只需要取消在配置文件中应用该拦截器,不管是否应用某个拦截器,对于整个框架不会有任何影响。这种设计哲学,是一种可插拔式的设计,具有非常好的可扩展性。

    拦截器可以动态地拦截发送到指定Action的请求,通过拦截器机制,我们可以在Action执行的前后插入的某些代码。通过这种方式,就可以把多个Action中需要重复指定的代码提取出来,放在拦截器里定义,从而提供更好的代码重用性。

   可见,拦截机制提现的是一种软件复用的原则。

拦截器可以拦截的请求和响应,主要用来拦截请求(只能拦截Action的请求和响应)。

Action的请求特点:无参的返回值是String类型的方法;

拦截器是在请求到达Action之前拦截,在Action请求响应到页面之前拦截;

实现拦截器的方式

1 实现Interceptor接口        (对类进行拦截)

2 继承AbstractInterceptor类     (对类进行拦截)

3 实现MethodFilterInterceptor类  (支持对方法的拦截)

自定义拦截器

步骤示例:

1 编写拦截器类

    拦截器类要继承AbstractInterceptor类,重写intercept方法,然后可以在方法内,调用action方法前后做相应的拦截处理。

    actionInvocation.invoke()方法是用来调用action方法的。

actionInvocation.invoke()方法是用来调用action方法的。    /** * 自定义拦截器 * 作用:计算action的执行时间 * @author Administrator */public class TimerInterceptor extends AbstractInterceptor {@Overridepublic String intercept(ActionInvocation actionInvocation) throws Exception {// 记录action执行的开始时间long start = System.currentTimeMillis(); // 获取系统当前时间// 调用下一个拦截器或者action请求String invoke = actionInvocation.invoke(); // 调用action的方法,返回值就是action返回的字符串// 记录acting执行完毕的时间long end = System.currentTimeMillis(); // 获取系统当前时间System.out.println("执行时间为" + ((end-start)/1000) + "秒");return invoke;}}

2 配置strutsxml文件

    a)在package下配置自定义拦截器

    b)在action中引用拦截器

配置示例:

<package name="user" extends="struts-default" namespace="/user"><!-- 配置自定义过滤器(该配置要在全局映射结果配置之前) --><interceptors><!-- 配置拦截器类 -->    <interceptor name="timer" class="com.soft863.interceptor.TimerInterceptor"></interceptor><!-- 定义自定义拦截器栈 -->    <interceptor-stack name="myStack">    <!-- 默认拦截器栈(必须先要引用struts2的默认拦截器栈) -->    <interceptor-ref name="defaultStack" />    <!-- 引入自定义拦截器 -->    <interceptor-ref name="timer" />    </interceptor-stack></interceptors><!-- 全局结果映射(在当前package下,对所有的Action都有作用) --><global-results><result name="error">/WEB-INF/error.jsp</result></global-results><action name="*" class="com.soft863.action.UserAction" method="{1}"><result name="registSuccess">/WEB-INF/pages/index.jsp</result><result name="input">/WEB-INF/pages/regist.jsp</result><interceptor-ref name="myStack" /> <!-- 在action中引入拦截器栈 --></action></package>

token拦截器

情景:

    提交添加内容的表单时,可能会出现用户重复点击提交按钮提交表单,这种情景下,可能会往数据库中插入多条相同的数据(即脏数据)。可以使用token拦截器对请求进行过滤。

token拦截器

    token拦截器会在请求到action之前,生成一个令牌,给页面保存一份,服务器保存一份,当页面请求服务器时,服务器会对比页面和服务器中保存的token,比较相同则服务器中保存的令牌会删除掉,那么当页面再次重复提交时,页面有令牌,而服务器匹配不到该令牌,则会把该请求过滤掉,从而可以解决上面情景中的情况。

 

这个tokenstruts提供的,直接使用即可。

 

token拦截器的使用

1 action控制器必须继承ActionSupport

2 在对应表单页面中的form标签中使用s:token设置令牌;

    <s:token></s:token><!-- 首先要引入struts2标签库-->

    该标签在页面中生成的源码样子为:

     <input type="hidden" name="struts.token.name" value="token" />

     <input type="hidden" name="token"

     value="284OOLHSJFEDWHJ2VFIWO2MXAGWEVPKA" />value值每次刷新页面会更新

3 在提交请求对应的action中配置token拦截器;

    <interceptor-ref name="defaultStack" />

    <interceptor-ref name="token" />

4 如果产生重复提交,需要设置对应的resultname要为invalid.token

示例:

1 Action控制器继承ActionSupport

2 在页面form标签中设置s:token

    <s:token></s:token><!-- 首先要引入struts2标签库-->

3 xmlaction中配置token拦截器

    对同一个action中的某个请求使用token拦截一般是单独配置该请求,如下:

    注:同一action配置*号和具体的name属性值时,struts的匹配规则是先匹配具体的,然后匹配*号。

<action name="*" class="com.soft863.action.UserAction" method="{1}"><result name="registSuccess">/WEB-INF/pages/index.jsp</result><result name="input">/WEB-INF/pages/regist.jsp</result><interceptor-ref name="myStack" /> <!-- 在action中引入拦截器栈 --></action><!--对action中的regist请求添加token拦截--><action name="regist" class="com.soft863.action.UserAction" method="regist"><result name="registSuccess">/WEB-INF/pages/index.jsp</result><result name="input">/WEB-INF/pages/regist.jsp</result><result name="invalid.token" type="redirectAction">../regist</result><!-- 配置token拦截器跳转到的视图 -->该配置说明看4步骤<interceptor-ref name="defaultStack" /> <!-- 首先引入struts2默认拦截器栈 --><interceptor-ref name="token" /> <!-- 引入token拦截器 --></action>

4 配置重复提交跳转到的视图,resultname要为invalid.token

<!-- 在action中配置token拦截器跳转到的视图 --><result name="invalid.token" type="redirectAction">../regist</result>

Struts2的文件上传

首先文件上传要将表单的enctype属性设置为multipart/form-data

(了解)表单的enctype属性有三个值:

    1 application/x-www-form-urlencoded:这是默认的编码方式,它只处理表单域里的value属性值,采用这种编码方式的表单会将表单域的值处理成URL编码。

    2 multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数里。

    3 text/plain:这种编码方式当表单的action属性为mailto:URL的形式时比较方便,这种方式主要适用于直接通过表单发送邮件的方式。

单文件上传

步骤:

1 设置struts2常量

2 添加jar包:commons-io.xxx.jarcommon-fileupload.xxx.jar

3 设置表单属性:enctype=”multipart/form-data”

4 在实体中提供三个变量,并提供对应的settergetter方法

    File img; // 上传的文件

    String imgFileName; // 文件名

    String imgContentType; // 文件类型

    注意:标红的部分要一致。

5 struts.xml文件中配置文件上串的常量

    struts.multipart.saveDir:指定上传文件保存的临时路径(默认在C盘的某个路径下)

    struts.multipart.maxSize:指定上传文件的最大字节数

    示例:

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

上传图片的后台保存处理:

(在上传请求的方法里写)

// 对上传文件进行处理File img = user.getImgs();// 获取upload上传路径String uploadPath = ServletActionContext.getServletContext().getRealPath("/upload");// 获取上传图片的后缀String ect = user.getImgsFileName().substring(user.getImgsFileName().lastIndexOf("."));// 生成唯一的图片名String imgName = UUID.randomUUID().toString() + ect;// 创建保存上传图片文件File file = new File(uploadPath);// 判断上传路径是否存在if(!file.exists()) {file.mkdirs();}FileUtils.copyFile(img, new File(uploadPath, imgName)); // 将上传图片从临时路径copy到上传路径下

多文件上传

多文件上传,将该三个变量设置为数据类型即可。

表单属性设置

<input type=”file” name=”img” multiple=”multiple” accept=”image/*” />

multiple属性是设置可以选择多个文件。(下拉列表多选也是设置该multiple属性即可)

accept属性是设置文件的上传类型,*表示所有类型的图片,也可以写成具体的类型

配置上传拦截器

struts2配置文件中配置文件上传拦截器:

<interceptor-ref name="fileUpload"><param name="allowedTypes">image/*</param><param name="maximumSize">2000000000</param></interceptor-ref><interceptor-ref name="defaultStack" /><!-- 默认拦截器 -->

注:上传文件拦截器要配置在Struts2默认拦截器之前;因为在文件上传时,如果配置文件上传拦截器,那么文件上传拦截器要配置在默认拦截器之前。因为文件上传拦截器就是默认拦截器中的一个拦截器,对上传拦截器进行配置后,如果上传拦截器写在默认拦截器后面,那么默认拦截器是只加载一次的,也就是加载完默认拦截器后,就不会在加载默认拦截器后面的上传拦截器,所以上传拦截器要写在默认拦截器之前。

Struts2的文件下载

文件的下载要点:

    1 提供下载请求;

    2 提供一个以get开头返回InputStream的方法;

    3 struts.xml中配置下载信息

    提供result标签,type属性设置为stream

步骤

1 提供以get开头的、返回InputStream的方法和下载的请求方法

// 请求方法public String download() {return "success";}// 以get开头的、返回InputStream的方法public InputStream getImgInputStream() {// 获取页面参数Integer id = this.getModel().getId();// 根据id查询用户头像路径String photo = "f745f8a0-5af6-41e8-895e-cc26ae0efaf6.bmp";// 获取文件路径String path = ServletActionContext.getServletContext().getRealPath("/upload");File file = new File(path, photo);try {this.getModel().setImgsFileName(URLEncoder.encode("课程表.png", "UTF-8"));return new FileInputStream(file);} catch (FileNotFoundException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}return null;}

2 配置struts.xml文件

<!-- 配置下载的信息 --><action name="download" class="com.soft863.action.UserAction" method="download"><result name="success" type="stream"><!-- 指定下载的流信息 --><!-- 指定下载文件的输入流方法名 --><param name="inputName">imgInputStream</param><param name="contentDisposition"><!-- 指定下载文件的名 -->attachement;fileName=${imgsFileName}                </param>                <!-- 指定下载文件的类型 --><param name=”contentType”>image/*</param></result></action>

ValueStackStack

valueStack :值栈,可以从里面获取Action中的成员属性和错误信息,形式为List格式的数据存储。

Stack: map格式的栈,可以用里面获取 request,session,application,attr,map

valueStack获取方式:<s:property value="值栈中的key">

Stack获取方式:<s:property value="#stack中的key">

可以使用EL表达式直接获取例如${key}

Struts2标签库

导入struts标签库:

<%@taglib uri="/struts-tags" prefix="s" %>

Strust2的匹配规则

同一个Actionname配置的有*号和具体的name值,那么struts2会先匹配具体的,如果没有确定的会再匹配*号,都没有则返回404

拦截器

默认拦截器

如果要对默认拦截器进行参数设置,可以直接在action配置拦截器,而不需要提供defaultStack

如果非要提供默认拦截器,则必须配置在后面。

注:在文件上传时,如果配置文件上传拦截器,那么文件上传拦截器要配置在默认拦截器之前。因为文件上传拦截器就是默认拦截器中的一个拦截器,对上传拦截器进行配置后,如果上传拦截器写在默认拦截器后面,那么默认拦截器是只加载一次的,也就是加载完默认拦截器后,就不会在加载默认拦截器后面的上传拦截器,所以上传拦截器要写在默认拦截器之前。

其他拦截器(即自定义拦截器)

其他拦截器必须配置要默认拦截器,并且默认拦截器要配置在其他拦截器之前。

校验器

校验器是对页面参数的校验。

注:使用校验器的前提是必须继承ActionSupport

基于代码的校验

基于代码校验方式一

    a)继承ActionSupport

    b)重写ActionSupportvalidate()方法。

    注:i validate的校验,如果控制器在值栈中有错误信息,则直接可以在对应的页面展示;

       ii 校验器失败默认会跳转到resultname=input的视图;

       iii 这种校验方式对action的所有请求都进行了数据校验;

示例:

a)继承ActionSupport

b)重写ActionSupportvalidate()方法

/*** 校验方法*/@Overridepublic void validate() {User user = this.getModel();if(user != null) {if(user.getUserName()==null||"".equals(user.getUserName())) {// 将错误信息保存到值栈中this.addFieldError("usernameErr", "用户名不能为空!");}}}

c)配置xml文件

当校验失败时,默认会跳转到resultname=input的视图;

<action name="test" class="com.soft863.action.UserAction" method="test"><result name="success">/WEB-INF/pages/regist.jsp</result><!-- 校验失败默认是跳转到input视图 --><result name="input">/WEB-INF/pages/regist.jsp</result></action>

d)在前台获取错误信息

值栈中的情况:


获取方式

    1 ${fieldErrors["usernameErr"][0] }

    2 <s:fielderror value="usernameErr" /> // 使用struts标签获取

基于代码校验方式二

提供一个方法,方法名:validateXxxxXxxx代表的是Action中对应的请求方法名,首字母大写。

注:这种方式只会对某一个请求进行校验,而不是像上面的方式对action中的请求都进行校验。

注意:请求该方法时,不要写validate

示例:

步骤只需将方式一中的步骤2改为如下代码即可:

/** * 校验方法 */public void validateRegist() {User user = this.getModel();if(user != null) {if(user.getUserName()==null || "".equals(user.getUserName())) {this.addFieldError("usernameErr", "用户名不能为空!");}}}

给方法对应的请求地址:http://localhost:8081/day0724_struts2/user/regist,不要加validate

基于配置文件的校验

1 编写规则文件,在xwork-core-2.3.30.jar中,com.opensymphony.xwork2

.validator.validators包下有一个default.xml文件,该文件中配置了内置的校验器。

xwork-core-2.3.30.jar中,提供的有xwork-validator-1.0.3.dtd文件,可以获取校验配置头信息。

<!DOCTYPE validators PUBLIC  "-//Apache Struts//XWork Validator 1.0.3//EN"  "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"><validators>       ......</validators>

2 xml配置校验器的命名规则

    a)对一个Action所有请求进行校验:ActionClassName-validation.xml

    b)Action中的某个请求进行校验:ActionClassName-请求名-validation.xml

    c)Action中的某一个方法不进行校验:ActionClassName-validate.xml

    并对不进行校验的方法添加注解@SkipValidation

    注:校验器的配置文件xml要和Action放在同一目录下

校验器类型

required :该校验器可以接受一个参数fieldName制定属性名

requiredstring:必填字符串校验器(也就是内容不可为空),该校验器可以接受filedName,和trim两个参数

int:整数校验器,可以接受三个参数fieldName , min , max

long :长整数校验器,可以接受三个参数fieldName , min , max

short:短整数校验器,可以接受三个参数fieldName , min , max

double:双精度校验器,可以接受三个参数fieldName , min , max

date:日期校验器,可以接受三个参数fieldName , min , max

expression  :表达式校验器,它是一个非字段校验器,所以不能用在字段校验器中。支持一个参数expression,该表达式基于valueStack进行求值,返回true时才通过。

fieldexpression:字段表达式校验器,接受2个参数fieldNameexpression

email:邮箱校验器,接受参数fieldName

url:网址校验器,接受参数fieldName

stringlength:字符串长度校验器,接受四个参数fieldName , minLength , maxLengthtrim

regex:正则表达式校验器,接受三个参数fieldNameregexcaseSensitive(指定在正则表达式是否区分大小写,该参数是可选的,默认为true)

基于配置文件的校验方式一:字段校验器配置风格

<validators><field name="username"><!-- 校验字段 --><field-validator type="stringlength"><!--校验类型--><param name="minLength">5</param><!-- 校验类型的属性 --><param name="maxLength">20</param><param name="trim">true</param><message><!-- 校验错误信息 -->用户名的长度必须在${minLenght}和${maxLength}之间</message></field-validator></field></validators>

示例:

1 对一个Action的所有请求进行校验

    创建UserAction-validation.xmlxml文件内容如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC  "-//Apache Struts//XWork Validator 1.0.3//EN"  "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"><validators><field name="userName"><field-validator type="stringlength"><param name="minLength">5</param><param name="maxLength">20</param><param name="trim">true</param><message>用户名的长度必须在${minLenght}和${maxLength}之间</message></field-validator><field-validator type="requiredstring"><param name="trim">true</param><message>用户名不能为空!</message></field-validator></field></validators>

注:获取错误信息的方式同基于代码校验的获取方式相同。

2 Action中的某个请求进行校验,只需将文件名按照命名规则命名即可,其他步骤相同。

3 Action中的某个请求不进行校验

    创建ActionClassName-validation.xml文件,在不进行校验的方法上加@SkipValidation注解。

基于配置文件的校验方式二:非字段校验器配置风格

<validators><validator type="required"><param name="fieldName">user.username</param><message>用户名不能为空</message></validator></validators>

示例:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC  "-//Apache Struts//XWork Validator 1.0.3//EN"  "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"><validators>  <validator type="regex"><!-- 校验类型 -->   <param name="fieldName">userName</param><!-- 校验字段 -->   <param name="regex">\w{6,20}</param>   <message>   用户名长度必须要在6到20。   </message></validator></validators>

注:只需将配置文件中的校验方式该为这种书写方式即可。

国际化配置

Struts2提供了很多加载国际化资源文件的方式,最简单,最常用的就是加载全局的国际化资源文件,加载全局的国际化资源文件的方式通过配置常量来实现。

1 只需要配置struts.custom.i18n.resources常量即可。

<constant name="struts.custom.i18n.resources" value="message" />

2 国际化配置文件名为 :

中文配置: message_zh_CN.properties

英文配置: message_en_US.properties

资源文件的内容为key=value格式

3 Action中可以通过getText(key , args...)方法来获取国际化内容,Action需继承ActionSupport

jsp中使用 <s:text name= "key" /> 来获取国际化内容

引入s标签方式:<%@taglib uri="/struts-tags" prefix="s" %> 

Struts2 - json的集成

struts2中安装json插件,json插件提供了一种名为JsonResultType,一旦为某一个Action指定了一个类型为jsonResult,则该Result无需映射到任何视图资源。因为Json插件会负责将Action里面的状态信息序列化成JSON格式的数据,并将该数据返回客户端页面的JavaScript

添加struts2-json-plugin-2.3.30.jar,在struts-2.3.33-all\struts-2.3.33\lib下。

<package name="json" extends="json-default" namespace="/"><action name="*_*" class="com.struts.action.{1}Action" method="{2}"><result type="json">         <!--配置要转换的json,不配置则将所有属性转为json-->        <param name="root"></param>        <!-- 防止json返回在IE中下载,同时设置编码 -->        <param name="contentType">text/html;charset=utf-8</param>        <!--添加白名单,对名单中的属性返回json-->         <param name="includeProperties">username,map</param>         <!--添加黑名单,对名单中的属性不生成json-->         <param name="excludeProperties">username,map</param>         <!--配置是否忽略继承属性,默认为true,设置为false,父类属性也会转json-->         <param name="ignoreHierarchy">false</param></result></action></package>

注:rootincludeProperties,excludeProperties配置的属性在action中必须提供get,set方法

步骤:

1 引入struts2-json-plugin-2.3.30.jar,在struts-2.3.33-all\struts-2.3.33\lib下;

2 定义一个packageextends=json-default

3 action标签下的result标签的type=”json”;

4 详细配置

<package name="json" extends="json-default" namespace="/json"><action name="test" class="com.soft863.action.UserAction" method="test"><result type="json"><param name="root"></param><param name="contentType">text/html;charset=utf-8</param></result></action></package>

a当Action实现ModelDriven时,<param name="root"></param>标签体中什么都不写,默认将Model转成json返回,如果要返回其他数据,将其定义为成员变量,提供setget方法,在标签体中指定返回的数据即可。

示例:

<package name="json" extends="json-default" namespace="/json"><action name="test" class="com.soft863.action.UserAction" method="test"><result type="json"><param name="root">list</param><!-- 指定返回list --><param name="contentType">text/html;charset=utf-8</param></result></action></package>

b)当Action没有实现ModelDriven接口时,<param name="root"></param>标签体中什么都不写,默认返回将所有的属性转成json返回,如果要返回其他数据,将其定义为成员变量,提供setget方法,在标签体中指定返回的数据即可。

OGNL表达式

OGNL(Object-Graph Navigation Language):对象图导航语言。

OGNL表达式必须要配合s标签使用。

OGNL表达式访问上下文

paramters

包含当前http请求的map参数

#paramters.id[0] 相当于

request.getParamter(id)

request

包含当前HttpServletRequest的属性map

#request.name相当于

request.getAttribute(name)

session

包含当前HttpSession的属性map

#session.name相当于

session.getAttribute(name)

application

包含当前应用ServletContext的属性map

#application.name相当于

application.getAttribute(name)

attr

用于访问request->session->applicaiton中的属性

#attr.name相当于按顺序从以上三个范围内读取name.读到为止

1 往前台传递数据

ServletActionContext.getRequest.setAttribute(key, value); // Servlet API方式

ActionContext.getContext().put(key, value); // Struts API方式

2 ActionContext

ActionContxt就是Action的上下文,就是struts2的值栈和栈中的信息。

使用ActionContext.getContext().put(key, value)方法向前台传数据,如果是ModelAction,则数据存放在值栈中,如果不是ModelAction,则数据存放在栈中。

3 获取struts2请求参数

Map<String, Object> parameters = ActionContext.getContext().getParameters();

4 获取request作用域

Map<String, Object> request = ActionContext.getContext().getContextMap();

注:这里获取的request只是相当于Servlet中的request,但两者的含义并非相同。

5 获取session作用域

Map<String, Object> session = ActionContext.getContext().getSession();

注:同request中的注。

6 获取application作用域

Map<String, Object> application = ActionContext.getCOntext().getApplication();

注:同request中的注。

7 往域中存放值

使用put(key, value)方法;

    request.put(key, value);

    session.put(key, value);

    application.put(key, value);

示例:

    request.put("a", "request");

    session.put("a", "session");

    application.put("a", "application");

注:在页面使用EL表达式获取值,同jsp中的EL表达式获取方式相同,EL表达式的查找规则页相同。

${a }${sessionScope.a }${applicationScope.a }

8 struts2标签

a)获取栈中的值

<s:property value=”#session.a” /><!-- value中写的就是OGNL表达式-->

OGNL表达式使用${}

${ }在下面两中情况下,括号中写的表达式叫OGNL表达式:

    a 在国际化资源文件中,引用OGNL表达式;

    b Struts2框架的配置中引用OGNL表达式;

    c 在校验器配置文件中,使用${}也是OGNL表达式;

OGNL表达式#的作用

1 访问requestsessionapplicationparamtersattr

2 构造map集合

    #{'name':'zhangsan','sex':''}

    示例:<s:set var="abcd" value="#{'name':'zhangsan','sex':''}"></s:set>

3 用于过滤和投影集合

    books.{?#this.price < 100}

    ? 代表获取满足条件的所有数据

    ^ 代表获取满足条件的第一条数据

    $ 代表获取满足条件的最后一条数据

OGNL表达式中使用%{}

a %{}可以取出值栈中的Action对象,直接调用它的方法。

b 如果Action继承了ActionSupport,那么在页面标签中可以使用%{getText('key')}获取国际化信息

例如:国际化  %{getText('key')}

OGNL表达式top语法

<s:property value=”[1].top”/><s:property value=”[2].top”/>

OGNL表达式@语法

1 配置常量支持访问静态属性/方法

struts.ognl.allowStaticMethodAccess

2 表达式语法:

    @类路径@静态属性/静态方法

    @@静态方法 代表调用的是Math类中的方法

原创粉丝点击