Struts2日常笔记

来源:互联网 发布:蓝带 知乎 编辑:程序博客网 时间:2024/06/08 05:52

花了三天时间看了一下Struts2,把学到的知识小节一下,方便日后查看。

第一节:Struts2的安装。

去http://struts.apache.org/下载Struts 2.3.30版本(2.5.2配置不好filter),可以直接下载struts-2.3.30-min-lib.zip,然后用eclipse新建一个Dynamic Web Project,将这些lib放到工程下WebContext/WEB-INF/lib目录下就可以了。
然后开始配置WEB-INF下的web.xml文件。这里直接新建一个struts2过滤器即可。

<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>

这样,Struct2项目就配置完成了。

第二节:Struts2核心知识

在Servlet中,通过request来进行数据传输。那么Struts2是通过什么机制来进行数据传输的呢?
总的来说,Struts2是通过在struts.xml中配置action,给定一个name到一个类中执行,并能够通过结果返回到给定的url。
比如我们建一个HelloWorldAction继承ActionSupport,里面含有一个name变量,然后设定好get、set方法。
然后在struts.xml中设置一个Action,比如:

<action name="hello" class="cn.tth.action.HelloWorldAction">    <result name="success">/hello.jsp</result></action>

这样在hello.jsp中就可以使用${name }来获取传过来的参数,比如我们访问http://localhost:8080/hello/hello?name=abc就可以得到abc。

Action设置数据不但可以是基本的数据类型,还可以是一个JavaBean,比如是一个User对象user,那么可以在jsp中通过user.name获取。

下面重点来讲一讲struts.xml配置。
首先是package标签,有四个主要属性:
- name 表示包名
- extends 表示继承,一般要继承struts-default
- namespace 表示包命名空间
- abstract 表示抽象包,抽象包内没有Action
然后是action标签,是包含在package标签里的,主要有三个属性:
- name action名
- class 处理类
- method 处理类调用的方法,默认是execute方法
在action标签里是result标签,主要有两个属性,
其中一个name来判断action处理类里返回的值,然后标签里决定下一步跳转到哪里。
type是要重点讲解的,主要常用的几个值:
- dispatcher 默认值,内部转发
- redirect 重定向
- chain 链条,可以把一个action链到其他的action
- redirectAction 重定向到action
- freemarker freemarker 模版
- httpheader 返回一个已配置好的HTTP头信息响应
- stream 将原始数据作为流传递回浏览器端
- velocity 呈现Velocity 模板
- xslt 该XML可以通过XSL模板进行转换
- plaintext 返回普通文本类容
除此之外,可以在全局配置result标签,比如要设置一个错误页,就可以设置一个全局的result,所有包里都可以共享这个页面。
另外,可以用<include file="" ></include>来包含其他的xml文件,使得原文件没有那么冗余。

第三节 struts2拦截器

拦截器,顾名思义,就是在访问Action或者Action的某个方法之前或之后进行拦截。
要实施拦截器,首先要创建一个类实现Interceptor接口。
比如这里要实现一个登录的拦截器,功能是在你没有登录的情况下不能直接访问内部页面。
首先建立一个LoginInterceptor类实现,Interceptor接口,然后对当前Session中的currentUser变量进行判断,如果为空说明还没有登录,返回error,否则正常执行。

public class LoginInterceptor implements Interceptor {    private static final long serialVersionUID = 1L;    @Override    public void destroy() {        System.out.println("LoginInterceptor destroy");    }    @Override    public void init() {        System.out.println("LoginInterceptor init");    }    @Override    public String intercept(ActionInvocation invocation) throws Exception {        System.out.println("LoginInterceptor执行之前");        ActionContext actionContext = invocation.getInvocationContext();        Map<String, Object> session = actionContext.getSession();        Object currentUser = session.get("currentUser");        String result = null;        if (currentUser != null) {            result = invocation.invoke();        } else {            HttpServletRequest request = (HttpServletRequest) actionContext.get(ServletActionContext.HTTP_REQUEST);            request.setAttribute("error", "请先登录");            result = "error";        }        System.out.println("LoginInterceptor执行之后");        return result;    }}

在UserAction中,继承ActionSupport类,重写execute执行方法。

public class UserAction extends ActionSupport {    private static final long serialVersionUID = 1L;    private UserService userService = new UserService();    private User user;    private String error;    @Override    public String execute() throws Exception {        if (userService.login(user)) {            ActionContext actionContext = ActionContext.getContext();            Map<String, Object> session = actionContext.getSession();            session.put("currentUser", user);            return SUCCESS;        } else {            setError("用户名或密码错误");            return ERROR;        }    }    public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }    public String getError() {        return error;    }    public void setError(String error) {        this.error = error;    }}

最后在struts.xml中注册拦截器以及UserAction。

<struts>    <package name="manage" extends="struts-default">        <interceptors>            <interceptor name="loginInterceptor" class="cn.tth.interceptor.LoginInterceptor"></interceptor>        </interceptors>        <global-results>            <result name="error">error.jsp</result>        </global-results>        <action name="user" class="cn.tth.action.UserAction">            <result name="success">success.jsp</result>            <interceptor-ref name="defaultStack"></interceptor-ref>        </action>        <action name="user2" class="cn.tth.action.User2Action">            <result name="success">success.jsp</result>            <interceptor-ref name="loginInterceptor"></interceptor-ref>            <interceptor-ref name="defaultStack"></interceptor-ref>        </action>    </package></struts>

首先在interceptors标签中注册拦截器,然后在UserAction标签中要引入默认拦截器<interceptor-ref name="defaultStack"></interceptor-ref>,在其他的Action中(比如user2)要加上登录拦截器<interceptor-ref name="loginInterceptor"></interceptor-ref>,这样如果进入user2时就会检测是否已经登录成功,如果登录不成功则会返回到global-results中的error标签。

第四节 值栈与OGNL

值栈是对应每个请求对象的一套内存数据的封装,Struts2会给每个请求创建一个新的值栈。简单的说就是Action的堆栈。
OGNL是对象图导航语言Object-Graph Navigation Language 的缩写,它是一种功能强大的表达式语言。
使用OGNL能够很容易的访问ValueStack中的数据,这里引入Struts2自带的自定义标签,使用<%@ taglib prefix="s" uri="/struts-tags"%>引入,使用<s:property value=”account” />进行调用。
OGNL访问ActionContext数据时,在访问某个范围时前面要加#号,比如

  • #parameters用来请求参数,相当于request.getParameter()
  • #request用来请求作用域中的数据,相当于request.getAttribute()
  • #session用来请求会话作用域中的数据,相当于session.getAttribute()
  • #application用来请求应用程序作用域中的数据,相当于application.getAttribute()
  • #attr 按照page request session application 顺序查找值
    下面我们来看一些例子,使用OGNL来访问值栈、session、application以及集合对象、Map对象。
    我们建一个HelloWorldAction,里面execute方法对值栈等进行设置值。
public class HelloWorldAction implements Action {    private Student student;    private List<Student> students;    private Map<String, Student> studentMap;    @Override    public String execute() throws Exception {        ActionContext actionContext = ActionContext.getContext();        // 获取狭义上的值栈        ValueStack valueStack = actionContext.getValueStack();        valueStack.set("name", "张三(valueStack)");        valueStack.set("age", 11 + "(valueStack)");        Map<String, Object> session = actionContext.getSession();        session.put("name", "王五(session)");        session.put("age", "13(session)");        Map<String, Object> application = actionContext.getApplication();        application.put("name", "招六(application)");        application.put("age", "14(application)");        student = new Student("stu哈", 17);        students = new ArrayList<Student>();        students.add(new Student("stu1", 111));        students.add(new Student("stu2", 222));        studentMap = new HashMap<>();        studentMap.put("goodStudent", new Student("stump1", 1111));        studentMap.put("badStudent", new Student("stump2", 2222));        return SUCCESS;    }    public Student getStudent() {        return student;    }    public void setStudent(Student student) {        this.student = student;    }    public List<Student> getStudents() {        return students;    }    public void setStudents(List<Student> students) {        this.students = students;    }    public Map<String, Student> getStudentMap() {        return studentMap;    }    public void setStudentMap(Map<String, Student> studentMap) {        this.studentMap = studentMap;    }}

之后对struts.xml进行正常设置,然后在jsp中接受这些值。

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title><%    request.setAttribute("name", "李四(request)");    request.setAttribute("age", "12(request)");%></head><body>    狭义上的值栈数据:    <s:property value="name" />    <s:property value="age" />    <br />    <s:property value="#parameters.name" />    <s:property value="#parameters.age" />    <br />    <s:property value="#request.name" />    <s:property value="#request.age" />    <br />    <s:property value="#session.name" />    <s:property value="#session.age" />    <br />    <s:property value="#application.name" />    <s:property value="#application.age" />    <br /> ognl访问javaBean对象    <s:property value="student.name" />    <s:property value="student.age" />    <br /> ognl访问list集合    <s:property value="students[0].name" />    <s:property value="students[0].age" />    <s:property value="students[1].name" />    <s:property value="students[1].age" />    <br /> ognl访问map    <s:property value="studentMap['goodStudent'].name" />    <s:property value="studentMap['goodStudent'].age" />    <s:property value="studentMap['badStudent'].name" />    <s:property value="studentMap['badStudent'].age" /></body></html>

另外OGNL也可以访问静态方法和属性。
比如我们设置一个静态类:

public class MyStatic {    public static final String str = "这是静态对象";    public static final String printUrl() {        System.out.println("http://www.baidu.com");        return "http://www.baidu.com";    }}

在jsp中就可以直接访问静态属性和方法,不过访问静态方法要在struts.xml中设置一下:<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>

<body>    访问静态属性:    <s:property value="@cn.tth.common.MyStatic@str" />    <br /> 访问静态方法:    <s:property value="@cn.tth.common.MyStatic@printUrl()" /></body>

第五节 struts2标签

Struts2自定义了一套标签,非常非常的强大,这里介绍一下常用的。
数据标签:
- Property 标签:输出OGNL 表达式的值;
- Set 标签:设置变量;
- Bean 标签:定义javaBean 对象
- Date 标签:日期标签
- Debug 标签:调试标签
- Url&a 标签:超链接标签
- Include 标签:动态包含标签
控制标签
- Ifelse 标签:条件判断标签
- Iterator 标签:遍历标签
- Append 标签:叠加标签
- Generator 标签:分隔标签
- Merge 标签:组合标签
- Sort 标签:排序标签
- Subset 标签:截取标签
界面标签
- Form 标签:表单提交标签
- Text 标签:文本标签
- Radios 标签:单选标签
- Checkboxlist 标签:复选框标签
- Select 标签:下拉框标签
具体一些例子可以去官方网站下载doc里找。

第六节 Struts2国际化

这一节说一下如何让一个网页能够满足国际化标准,比如在中国语言设置的zh-CN,就会显示中文,在美国语言设置的en-US,就会显示英文。简单地说就是实现多语言支持。
我们来做一个简单的例子。
在src目录下新建一个lang.properties文件,然后在里面输入welcomeInfo=\u6b22\u8fce,里面注意用Unicode转义字符,比如说我们创建一个中文的properties,名字则取为lang_zh_CN.properties,里面同样输入welcomeInfo=\u6b22\u8fce,再来创建一个英文的properties,名字取为lang_en_US.properties,里面输入welcomeInfo=welcome。这样我们在JSP中就可以使用

<s:text name="welcomeInfo">    <s:param>Jack</s:param></s:text>

用IE可以方便的更换语言来进行测试。

第七节 Struts2 验证框架

Struts2验证框架是基于struts2拦截器做的,并可以扩展,简洁易用。
我们先举一个内置验证的例子,比如我们做一个注册验证,使用验证框架会非常的方便。
首先我们创建一个User类,含有用户名、姓名、年龄、email以及主页。
然后创建一个注册Action:

public class RegisterAction extends ActionSupport {    private static final long serialVersionUID = 1L;    private User user;    @Override    public String execute() throws Exception {        System.out.println("传入的用户:" + user);        return SUCCESS;    }    public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }}

在它的同级目录下,我们要创建一个RegisterAction-validation.xml,用来进行注册验证。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"><validators>    <field name="user.userName">        <field-validator type="requiredstring">            <message>请输入用户名</message>        </field-validator>        <field-validator type="stringlength">            <param name="minLength">6</param>            <param name="maxLength">10</param>            <message>用户名必须在${minLength}和${maxLength}之间</message>        </field-validator>    </field>    <field name="user.name">        <field-validator type="requiredstring">            <message>请输入姓名</message>        </field-validator>    </field>    <field name="user.age">        <field-validator type="int">            <param name="min">18</param>            <message>年龄必须满18周岁</message>        </field-validator>    </field>    <field name="user.email">        <field-validator type="requiredstring">            <message>请输入邮件</message>        </field-validator>        <field-validator type="email">            <message>邮件格式不对</message>        </field-validator>    </field>    <field name="user.homePage">        <field-validator type="requiredstring">            <message>请输入主页</message>        </field-validator>        <field-validator type="url">            <message>主页格式不对</message>        </field-validator>    </field>    <validator type="expression">        <param name="expression"><![CDATA[!user.name.equals(user.userName)]]></param>        <message>用户名和真实姓名不能相同</message>    </validator></validators>

最后在register.jsp中就可以使用struts2自带的标签完成注册验证功能。

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body>    <s:actionerror />    用户注册    <s:form action="registerAction" method="post">        <s:textfield name="user.userName" label="用户名"></s:textfield>        <s:textfield name="user.name" label="真实姓名"></s:textfield>        <s:textfield name="user.age" label="年龄"></s:textfield>        <s:textfield name="user.email" label="邮件"></s:textfield>        <s:textfield name="user.homePage" label="主页"></s:textfield>        <s:submit value="注册"></s:submit>    </s:form></body></html>

这是使用已有的框架进行验证,下面说一下自定义验证,首先要把原有的validators.xml文件拷贝到src目录下,这里面包含了所有已有的验证登录,我们可以在最后加一条自己的验证。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC        "-//Apache Struts//XWork Validator Config 1.0//EN"        "http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd"><validators>    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>    <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>    <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>    <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>    <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>    <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>    <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>    <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>    <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>    <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>    <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>    <validator name="sensitive" class="cn.tth.validators.SensitiveWordValidators"/> </validators>

然后我们来写SensitiveWordValidators类,继承的是FieldValidatorSupport,实现了检查是否有敏感词汇。

public class SensitiveWordValidators extends FieldValidatorSupport {    @Override    public void validate(Object object) throws ValidationException {        String fieldName = this.getFieldName();        String value = (String) this.getFieldValue(fieldName, object);        if (!check(value)) {            this.addFieldError(fieldName, object);        }    }    public boolean check(String value) {        String sensitiveWords[] = { "敏", "感", "词", "汇" };        for (int i = 0; i < sensitiveWords.length; i++) {            if (value.indexOf(sensitiveWords[i]) > -1) {                return false;            }        }        return true;    }}

最后我们创建ValidationAction,并创建相应的ValidationAction-validation.xml。

public class ValidationAction extends ActionSupport {    private static final long serialVersionUID = 1L;    private String name;    @Override    public String execute() throws Exception {        System.out.println("姓名:" + name);        return SUCCESS;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"><validators>    <field name="name">        <field-validator type="requiredstring">            <message>请输入姓名</message>        </field-validator>        <field-validator type="sensitive">            <message>有敏感词汇</message>        </field-validator>    </field></validators>

最后可以在JSP中简单测试一下。

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body>    简单用户验证    <s:form action="validationAction" method="post">        <s:textfield name="name" label="用户名"></s:textfield>        <s:submit value="提交"></s:submit>    </s:form></body></html>

第八节 Struts2 文件上传和下载

Struts2 文件上传也是基于Struts2 拦截器实现的,传使用的是fileupload 组件。
这里用一个简单的例子来讲解一下文件上传的用法:
首先写一个FileUploadAction,这里面有一个File对象,这个name是文件表单的name,Struts是通过这个name来获取上传文件,上传文件名格式是name+”FileName”,上传文件类型格式是name+”ContentType”。

public class FileUploadAction extends ActionSupport {    private static final long serialVersionUID = 1L;    private File uploadFile; // 文件    private String uploadFileFileName; // 文件名    private String uploadFileContentType; // 文件类型    //此处省略一万个get、set方法    ...    @Override    public String execute() throws Exception {        System.out.println("文件名:" + uploadFileFileName);        System.out.println("文件类型:" + uploadFileContentType);        String filePath = "D:/" + uploadFileFileName;        File saveFile = new File(filePath);        FileUtils.copyFile(uploadFile, saveFile);        return SUCCESS;    }}

在struts.xml里正常配置完毕以后,就可以写一个JSP来测试一下,注意这里表单里有一个enctype要设置为multipart/form-data。

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@taglib prefix="s" uri="/struts-tags" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body><s:fielderror></s:fielderror><form action="upload" method="post" enctype="multipart/form-data">    文件:<input type="file" name="uploadFile"/><br/>    <input type="submit" value="提交"/></form></body></html>

如果要实现大文件上传,则需要在struts.xml里加上

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

下面来讲一下文件下载的方法,首先创建一个FileDownloadAction。

public class FileDownloadAction extends ActionSupport {    private static final long serialVersionUID = 1L;    private String fileName;    public InputStream getInputStream() throws Exception {        File file = new File("C:\\Users\\lenovo\\Desktop\\新建文本文档.txt");        this.setFileName("新建文本文档");        return new FileInputStream(file);    }    public String getFileName() throws Exception {        fileName = new String(fileName.getBytes(), "ISO8859-1");        return fileName;    }    public void setFileName(String fileName) {        this.fileName = fileName;    }}

配置一下struts.xml文件:

<action name="download" class="com.java1234.action.FileDownloadAction">    <result type="stream">        <param name="contentDisposition"> attachment;file=${fileName}</param>    </result></action>

然后主页直接点击链接到这个Action即可完成下载。

第九节 Struts2 防重复提交

当用户点击注册按钮时,由于网络延迟等种种因素,有可能会在一次提交表单之后多次重复点击提交按钮,为了防止这种情况发生,struts2也有相应的防重复提交机制。需要在struts.xml文件中配置Action时在里面加入tokenSession的拦截器。比如:

<action name="student" class="com.java1234.action.StudentAction"            method="add">    <result name="success">/success.jsp</result>    <interceptor-ref name="tokenSession"></interceptor-ref>    <interceptor-ref name="defaultStack"></interceptor-ref></action>

然后在登录的JSP表单中加入<s:token></s:token>

<form action="student" method="post">    <s:token></s:token>    姓名:<input type="text" name="student.name" /><br /> 年龄:<input        type="text" name="student.age" /><br /> <input type="submit"        value="提交" /></form>

可以在Action中睡眠5s来模拟延迟,这样当多次重复提交后台则会报出
八月 09, 2016 6:43:44 下午 com.opensymphony.xwork2.util.logging.jdk.JdkLogger warn
警告: Form token JD29HWEUP28KF89WLL7H14F3X6Q0YF8E does not match the session token null.
前台虽然点击了多次,但是后台只会提交一次,有效的防止了重复提交表单的情况。

1 0
原创粉丝点击