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.
前台虽然点击了多次,但是后台只会提交一次,有效的防止了重复提交表单的情况。
- Struts2日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- 日常笔记
- Design Support Library
- 130. Surrounded Regions
- 文件夹快捷键
- Effective C++_Item12笔记
- 加载JDBC-ODBC驱动器和连接数据库
- Struts2日常笔记
- 【HDU 杭电 1003 Max Sum】
- 译:应用笔记 在C中的简单面向对象编程
- LightOJ 1409 Rent a Car 费用流
- django admin上传文件和图片
- openpyxl - 学习目录
- HDU 2059 龟兔赛跑
- Python练习100例-4
- 关于libcurl下载数据不全的bug