Struts2学习笔记(二)

1. 自定义结果视图的类型(结果视图类型的应用)

CAPTCHA图像(随机验证码图像)

实现步骤:

(1)编写一个类实现com.opensymphony.xwork2.Result, 或者继承org.apache.struts2.dispatcher.StrutsResultSupport

package com.itheima.results;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.image.BufferedImage;

import java.io.OutputStream;

import java.util.Random;

import javax.imageio.ImageIO;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.Result;

public class CaptchaResult implements Result {

private int width = 100;

private int height = 25;

public void setWidth(int width) {

this.width = width;

}

public void setHeight(int height) {

this.height = height;

}

public void execute(ActionInvocation invocation) throws Exception {

//BufferedImage:代表内存图片

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

//Graphics:画笔

Graphics g = image.getGraphics();

//画边线

g.setColor(Color.GREEN);

g.drawRect(0, 0, width, height);

//填充背景色

g.setColor(Color.YELLOW);

g.fillRect(1, 1, width-2, height-2);

//干扰线

Random r = new Random();

g.setColor(Color.GRAY);

for(int i=0;i<15;i++)

g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));

//验证码

g.setColor(Color.RED);

g.setFont(new Font("宋体",Font.BOLD|Font.ITALIC, 18));

int x = 19;

for(int i=0;i<4;i++){

g.drawString(r.nextInt(10)+"",x, 20);

x+=20;

}

//ImageIO:输出图片给指定的流

OutputStream out = ServletActionContext.getResponse().getOutputStream();

ImageIO.write(image, "jpg", out);

}

}

. (2)在struts.xml 文件中声明定义的结果视图类型

<struts>

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

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

<result-types>

<result-type name="captcha" class="com.itheima.results.CaptchaResult"></result-type>

</result-types>

<action name="genCaptcha">

<result name="success" type="captcha">

<param name="width">200</param>----//这里可以动态改变验证码视图的长宽比例

<param name="height">50</param>

</result>

</action>

</package>

</struts>

(3). Jsp视图显示内容

<form action = "">

用户名:<input type= "text" name = "username"></input>

验证码:<input type = "text" name = "code"><img src="${pageContext.request.contextPath}/genCaptcha.action"/>

</form>

(4). 效果截图如下

2. 封装参数到JavaBean或action中(重点)

(1)Action或JavaBean中接收请求参数

两种方式:

(1)在动作类中成员变量给予初始值,即动作类中的字段有默认值

(2)在配置文件中注入动作类的参数值(静态参数设置)

步骤如下:

1)定义一个PersonAction类

public class PersonAction extends ActionSupport {

private String name = "刘小晨";

private String password;

private int age;

public String getName() {

return name;

}

public void setName(String name) {

System.out.println("调用了setName方法");

this.name = name;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String execute() throws Exception {

System.out.println(name+":"+password+":"+age);

return SUCCESS;

}

}

这里要为个成员变量设置相应的getter和setter方法

2)struts.xml文件的配置

<action name = "action1" class ="com.itheima.actions.PersonAction">

<param name ="name">崔召金</param>

<param name ="age">24</param>

<param name ="password">201026</param>

<result>/result.jsp</result>

</action>

访问:http://localhost:8080/day27_01_struts2Params/action1

网页返回结果如下

崔召金:201026:24

另外控制台打印出如下内容:

调用了setName方法

调用了setName方法

崔召金:201026:24

这里说明了,action自己给初始化name调用setName方法执行一次,另外一次是编码人员自己在sturts.xml中给name赋值时,又执行一次。

实际上是由一个叫做staticParams的拦截器做的(具体里面干了什么事,我真心搞不懂)

(3)表单请求参数,动态参数的注入(params)

方式一:用动作类作为模型action

Jsp页面内容:

<form action="${pageContext.request.contextPath}/action2" method="post">

用户名:<input type="text" name="name"/><br/>

<input type ="submit" value="保存"/>

</form>

Struts.xml文件中的配置如下:

<action name = "action2" class ="com.itheima.actions.PersonAction1">

<param name ="name">崔召金a</param>

<result>/result.jsp</result>

</action>

PersonAction1

public class PersonAction1 extends ActionSupport {

private String name = "刘小晨";

public String getName() {

return name;

}

public void setName(String name) {

System.out.println("调用了setName方法");

this.name = name;

}

public String execute() throws Exception {

System.out.println(name);

return super.execute();

}

}

总结:表单的字段输入域的name取值要和动作类的写属性名称一致。

结果如下:

调用了setName方法

调用了setName方法

Java编程经典

方式二:动作类和模型分开

Student类

package com.itheima.domain;

import java.io.Serializable;

public class Student implements Serializable {

private String name;

private int age;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

@Override

public String toString() {

return "Student [name=" + name + ", age=" + age + "]";

}

}

StudentAction动作类

package com.itheima.actions;

import com.itheima.domain.Student;

import com.opensymphony.xwork2.ActionSupport;

public class StudentAction extends ActionSupport {

private Student student = new Student();

public Student getStudent() {

System.out.println("调用了getStudent方法");

return student;

}

public void setStudent(Student student) {

System.out.println("调用了setStudent方法");

this.student = student;

}

public String execute() throws Exception {

System.out.println(student);

return NONE;

}

Jsp页面如下配置

<form action="${pageContext.request.contextPath}/saveStudent" method="post">

用户名:   <input type="text" name="student.name"/><br/>崔召金

年龄:     <input type="text" name="student.age"/><br/>23

<input type="submit" value="保存"/>

</form>

Sturts.xml文件配置代码如下:

<action name="saveStudent" class="com.itheima.actions.StudentAction"/>

控制台打印代码如下:

调用了getStudent方法

调用了getStudent方法

Student [name=崔召金, age=23]

执行的过程:

框架再调用StudentAction的getStudent(),方法,得到刚刚创建的对象

紧着着,调用student实例的setName和setAge方法,设置值。

方式三:模型驱动(ModelDriven)与valueStack有关

(1)使用模型驱动,关键是动作类的编写

package com.itheima.actions;

import com.itheima.domain.Customer;

import com.opensymphony.xwork2.ActionSupport;

import com.opensymphony.xwork2.ModelDriven;

//使用模型驱动:实现modeldrivern接口

public class CustomerAction extends ActionSupport implements ModelDriven<Customer>{

private Customer customer = new Customer();

public Customer getCustomer() {

return customer;

}

public void setCustomer(Customer customer) {

this.customer = customer;

}

@Override

public String execute() throws Exception {

System.out.println(customer);

return NONE;

}

public Customer getModel() {

return customer;

}

}

Customer类的编写

package com.itheima.domain;

import java.io.Serializable;

public class Customer implements Serializable {

private String name;

private String city;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getCity() {

return city;

}

public void setCity(String city) {

this.city = city;

}

@Override

public String toString() {

return "Customer [name=" + name + ", city=" + city + "]";

}

}

Jsp页面代码编写

<form action="${pageContext.request.contextPath}/saveCustomer.action" method="post">

用户名:<input type="text" name="name"/><br/>

城市:<input type="text" name="city"/><br/>

<input type="submit" value="保存"/>

</form>

Sturts.xml中的配置

<action name="saveCustomer" class="com.itheima.actions.CustomerAction"/>

原理:实际上由一个拦截器来完成的modelDriven

该拦截器会在执行动作方法前,把模型对象压到ValueStack值栈的栈顶。

控制台输出如下内容:

Customer [name=崔召金, city=上海]

3. 封装数据到Collection中

JSP页面代码

<body>

<form action="${pageContext.request.contextPath}/collectionAction1" method="post">

爱好:

<input type="checkbox" name="hobby" value="吃饭"/>吃饭

<input type="checkbox" name="hobby" value="睡觉"/>睡觉

<input type="checkbox" name="hobby" value="学java"/>学java

<input type="submit" value="保存"/>

</form>

<hr/>

<h2>批量添加员工信息</h2>

<form action="${pageContext.request.contextPath}/collectionAction2" method="post">

员工1:姓名:<input type="text" name="employees[0].name"/>薪水:<input type="text" name="employees[0].salary"/><br/>

员工2:姓名:<input type="text" name="employees[1].name"/>薪水:<input type="text" name="employees[1].salary"/><br/>

员工3:姓名:<input type="text" name="employees[2].name"/>薪水:<input type="text" name="employees[2].salary"/><br/>

<input type="submit" value="保存"/>

</form>

<h2>向Map中添加内容</h2>

<form action="${pageContext.request.contextPath}/collectionAction3" method="post">

员工1:姓名:<input type="text" name="emps['e1'].name"/>薪水:<input type="text" name="emps['e1'].salary"/><br/>

员工2:姓名:<input type="text" name="emps.e2.name"/>薪水:<input type="text" name="emps.e2.salary"/><br/>

员工3:姓名:<input type="text" name="emps.e3.name"/>薪水:<input type="text" name="emps.e3.salary"/><br/>

<input type="submit" value="保存"/>

</form>

</body>

Struts.xml文件的配置

<action name="collectionAction1" class="com.itheima.actions.CollectionAction"/>

<action name="collectionAction2" class="com.itheima.actions.CollectionAction"/>

<action name="collectionAction3" class="com.itheima.actions.CollectionAction"/>

Employee类的编写

package com.itheima.domain;

import java.io.Serializable;

public class Employee implements Serializable {

private String name;

private float salary;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public float getSalary() {

return salary;

}

public void setSalary(float salary) {

this.salary = salary;

}

@Override

public String toString() {

return "Employee [name=" + name + ", salary=" + salary + "]";

}

}

4. 自定义类型转换器:

对于大部分常用类型,开发者根本无需创建自己的转换器,Struts2内置了常见数据类型多种转换器

boolean 和 Boolean

char和 Character

int 和 Integer

long 和 Long

float 和 Float

double 和 Double

Date 可以接收 yyyy-MM-dd格式字符串

数组  可以将多个同名参数,转换到数组中

集合  支持将数据保存到 List 或者 Map 集合

java.util.Date类型的属性可以接收格式为2009-07-20的请求参数值。但如果我们需要接收格式为20091221的请求参数,我们必须定义类型转换器,否则struts2无法自动完成类型转换。

自定义类型转换器的编写:

1、编写一个类,继承StrutsTypeConverter

package com.itheima.convertor;

import java.text.DateFormat;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

//日期转换器:

/*

* String :12/31/2001 ---->Date

* Date---------->String:12/31/2001

*/

public class MyDateConvertor extends StrutsTypeConverter {

private DateFormat df = new SimpleDateFormat("MM/dd/yyyy");

//从字符串转换成日期

public Object convertFromString(Map context, String[] values, Class toClass) {

if(toClass==Date.class){

String value = values[0];//获取用户输入的参数值12/31/2001

try {

return df.parse(value);

} catch (ParseException e) {

e.printStackTrace();

}

}

return null;

}

//日期转换成字符串

public String convertToString(Map context, Object o) {

if(o instanceof Date){

Date d = (Date)o;

return df.format(d);

}

return null;

}

}

注册类型转换器

1.局部类型转换器

在action动作类所在的包中,新建一个名字为actionName-conversion.properties的文件

内容如下:

birthday=com.itheima.convertor.MyDateConverter(局部类型转换器)

2.全局类型转换器:

在web-inf/classes目录下新建一个名为:xwork-convesion.properties;

内容 如下:

java.util.Date =com.itheima.convertor.MyDateconverter

3.类型转换中的类型提示:

出现转换失败时的错误提示(conversionError拦截器完成的)

Struts.xml文件中的内容如下:

<struts>

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

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

<action name ="addUser" class = "com.itheima.actions.UserAction" method = "add">

<result>/success.jsp</result>

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

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

</action>

</package>

</struts>

Jsp页面中需要改动的地方:

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

。。。。。。。

<body>

<s:fielderror></s:fielderror>

。。。。。。。。。

出现转换失败,会被转向一个叫input的视图,并把错误信息提示封装到fieldError中。

在动作类所在的包中建立一个名称为“动作类名.properties”的配置文件,

内容如下:

invalid.fieldvalue.字段=你的提示信息

效果如下:

5.struts里的输入校验:

1. 输入校验

客户端校验  过滤正常用户的误操作,通过JS代码完成

服务器端校验,整个应用阻止非法数据的最后防线

2. 验证的途径:

1.编程式验证

userAction中覆盖方法

@Override

public void validate() {

//用户名不能为null或“”

if(StringUtils.isEmpty(username)){

addFieldError("username", "用户名不能为空");//   Map<String,String>key:字段名,value错误提示

}

}

如上一个方法的作用范围为所有的action动作。如果想只约束某个动作可以这么做。

<action name ="addUser" class = "com.itheima.actions.UserAction" method = "add">

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

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

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

</action>

<action name="UserEdit" class="com.itheima.actions.UserAction" method="edit">

<result>/success.jsp</result>

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

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

</action>

方式一:对指定的动作让其或略验证:

@SkipValidation

public String edit()

{

return SUCCESS;

}

方式二:只针对edit方法进行验证!

public String edit()

{

return SUCCESS;

}

public void validateEdit()

{

if(StringUtils.isEmpty(username)){

addFieldError("username", "用户名不能为空哦哦");

}

}

如上所示 :

只会对edit()方法做出验证:

验证不通过时,框架会给你转向一个叫做input的视图,使用struts2的<s:fieldError/>显示错误消息提示。

2. 声明式验证

针对所有方法进行验证:

在动作类所在的包中,建立一个名称为”动作类名-validation.xml”

内容如下:

针对某个动作进行验证:

在动作类所在的包中,建立一个名称为”动作类名-动作名称-validation.xml”

或者使用@SkipValidation

6 Struts2框架中声明式验证的内置验证器

他们都在xwork-core-*.jar包的

com.opensymphony.xwork2.validator.validators.default.xml中进行了定义。

常用的验证器:

requiredstring:字符串不能为null或空字符串。默认情况下会对数据进行trim后进行判断。

<!-- 写法形式一:可以给一个字段添加好多的验证规则 -->

<!-- 写法形式一:可以给一个字段添加好多的验证规则 -->

<field name = "username"><!-- 验证的字段名称 -->

<field-validator type="requiredstring"><!-- 不能为空 -->

<param name = "trim">false</param>

<message>用户名不能为空,你找骂</message>

</field-validator>

<field-validator type="stringlength"><!-- 验证字符串长度的 -->

<param name="minLength">3</param>

<param name="maxLength">9</param>

<message>用户名必须介于${minLength}~${maxLength}之间哦</message>

</field-validator>

</field>

<!-- 写法形式二:用于非字段性的验证

<validator type="requiredstring">

<param name="fieldName">username</param>

<message>用户名不能为空</message>

</validator>

7 自定义声明式验证器

1.编写一个类,继承com.opensymphony.xwork2.validator.validators.FieldValidatorSupport

StrongPasswordValidator类

package com.itheima.actions;

import com.opensymphony.xwork2.validator.ValidationException;

import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;

public class StrongPasswordValidator extends FieldValidatorSupport {

private int minLength  = -1;

public int getMinLength() {

return minLength;

}

public void setMinLength(int minLength) {

this.minLength = minLength;

}

//验证方法:针对不符合要求的内容进行判断,向Map中添加信息即可

//参数:object就是当前的动作对象

public void validate(Object object) throws ValidationException {

//获取要验证的字段名称

String fieldName = getFieldName();

Object fieldValue = getFieldValue(fieldName, object);

if(fieldValue==null)

return;

if(!isStrong((String)fieldValue)){

addFieldError(fieldName, object);

}

if((minLength>-1)&&((String)fieldValue).length()<minLength){

// 添加一个消息

addFieldError(fieldName, object);

}

}

//判断s是否强大

private static final String GROUP1 = "abcdefghijklmnopqrstuvwxyz";

private static final String GROUP2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

private static final String GROUP3 = "0123456789";

//判断密码是否强壮:至少一个大写字母、一个小写字母、一个数字

private boolean isStrong(String s) {

boolean ok1 = false;

boolean ok2 = false;

boolean ok3 = false;

int length = s.length();

for(int i=0;i<length;i++){

if(ok1&&ok2&&ok3)

break;

String character = s.substring(i,i+1);

if(GROUP1.contains(character)){

ok1 = true;

continue;

}

if(GROUP2.contains(character)){

ok2 = true;

continue;

}

if(GROUP3.contains(character)){

ok3 = true;

continue;

}

}

return ok1&&ok2&&ok3;

}

}

2.在WEB-INF\classes目录下建立一个固定名称validators.xml的配置文件,

3.UserAction-UserEdit-validation.xml中写如下代码:

<field name ="password">

<field-validator type ="strongpassword">

<message>您的密码不够强壮</message>

</field-validator>

</field>

验证两次密码是否一致

1.jsp中如下代码:

<s:actionerror>

2.UserAction-UserEdit-validation.xml中写如下代码:

<validator type="expression">

<param name="expression">

password==repassword

</param>

<message>两次密码必须一致</message>

</validator>

8. Struts2的国际化

1、配置全局国际化消息资源包

a.配置全局消息资源包

b、如何访问

l 在动作类中:

前提,动作类继承ActionSupport

l 在页面中:

或者

<s:text name="hello"></s:text>

l 自由指定消息资源包,借助struts2的有关国际化的标签:

如果消息资源包在com.itheima.resources.msg_zh_CN.properties

2. 配置局部消息资源包

一定要经过Action才行:

书写规范:在动作类所在包中,建立名字”动作类名-zh-CN.properties”的配置文件。动作类中访问,发现局部的比全局的优先级高。

3、包范围的消息资源包

也得经过action访问

书写有规范的,名称为package_zh_CN.properties,放在类的包中。可以被包中及子包的所有动作类来访问。

总结:

day27_00_struts2Result

day27_01_struts2Params

day27_02_struts2regist

day27_03_struts2i18n

9. struts2中的拦截器(框架功能核心)

1.过滤器与拦截器的对比

功能是一回事。

过滤器是Servlet规范中的技术,可以对请求和响应进行过滤。

拦截器是Struts2框架中的技术,实现AOP(面向切面)的编程思想,可以对请求动作进行拦截。

2. 自定义拦截器

步骤:

A. 编写一个类,直接或间接实现Interceptor接口。(拦截器会驻留内存),一般都选择继承AbstractInterceptor

public class MyInterceptor extends AbstractInterceptor {

public String intercept(ActionInvocation invocation) throws Exception {

System.out.println("拦截器执行前");

String result = invocation.invoke();

System.out.println("拦截器执行后"+result);

return result;

}

}

B. 需要在struts.xml中进行定义

C. 在动作配置中就可以使用了

知识点:除了要使用自定义的拦截器之外,还要使用defaultStack,可以这么办

方法一:(自己使用)

方法二:(大家都用的时候)

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

<interceptors>

<interceptor name="myinterceptor" class="com.itheima.interceptor.MyInterceptor"></interceptor>

<interceptor-stack name="mydefaultStack">

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

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

</interceptor-stack>

</interceptors>

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

</package>

<package name="p1" extends="mydefault">

<action name="action1" class = "com.itheima.action.MyInterceptorAction" method="add">

<result>/success.jsp</result>

</action>

</package>

3. 能够指定拦截的方法或不拦截的方法(自定义拦截器)

自定义拦截指定的方法是指对拦截器进行限制,对需要拦截的动作action进行拦截,具体步骤如下:

1.写一个action类CustomerAction类

package com.itheima.action;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class CustomerAction extends ActionSupport {

public String add()

{

System.out.println("调用add的service方法");

return SUCCESS;

}

public String edit()

{

System.out.println("调用edit的service方法");

return  SUCCESS;

}

public String login()

{

System.out.println("登录了哦");

ServletActionContext.getRequest().getSession().setAttribute("user","ppp" );

return SUCCESS;

}

}

2.编写一个拦截器类MyInterceptor1

public class MyInterceptor1 extends MethodFilterInterceptor {

protected String doIntercept(ActionInvocation invocation) throws Exception {

System.out.println("拦截了,嘿嘿");

return invocation.invoke();

}

}

3. struts.xml文件中这样编写:

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

<interceptors>

<!-- 自定义一个拦截器 -->

<interceptor name="myinterceptor" class="com.itheima.interceptor.MyInterceptor"></interceptor>

<interceptor name="myinterceptor1" class="com.itheima.interceptor.MyInterceptor1"></interceptor>

</interceptors>

<action name="action1" class = "com.itheima.action.MyInterceptorAction" method="add">

<interceptor-ref name="defaultStack"></interceptor-ref>       将默认的拦截器个补进来

<interceptor-ref name="myinterceptor"></interceptor-ref>      自定义拦截器类

<result>/success.jsp</result>

</action>

<action name="*" class ="com.itheima.action.CustomerAction" method="{1}">

<interceptor-ref name="myinterceptor1">

<param name="excludeMethods">edit</param>          将剑代码,在拦截器中俄一个参数excludedMethods=需要排除的动作

</interceptor-ref>

<result>/success.jsp</result>

</action>

</package>

10. 文件啊文件上传与下载

1、前提:

form表单的method必须是post

form表单的enctype必须是multipart/form-data

提供type=”file”的上传输入域.

2.单文件上传

JSP页面代码:

<body>

<s:actionerror/>

<hr/>

<s:fielderror></s:fielderror>

<form action="${pageContext.request.contextPath}/upload1.action" method="post" enctype="multipart/form-data">

用户名:<input type="text" name="username"/><br/>

靓照:<input type="file" name="photo"/><br/>

<input type="submit" value="上传"/>

</form>

</body>

Struts.xml文件代码如下:

<struts>

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

<constant name="struts.custom.i18n.resources" value="globa"></constant>配置全局的资源信息。(为信息回显做翻译)

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

<action name="upload1" class="com.itheima.action.UploadAction1" method="upload">

<interceptor-ref name="defaultStack">

<param name="fileUpload.allowedTypes">image/jpeg,image/png</param>允许上传的类型

<param name="fileUpload.allowedExtensionsSet">jpg,jpeg,png</param>允许上传文件的后缀名字

</interceptor-ref>

<result>/success.jsp</result>

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

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

</action>

</package>

</struts>

核心action类编写如下:

package com.itheima.action;

import java.io.File;

import java.io.IOException;

import org.apache.commons.io.FileUtils;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

//文件上传:fileUpload拦截器完成的

public class UploadAction1 extends ActionSupport {

private String username;         //text文本域中的名称保持一致

private File photo;     //和表单的上传字段名保持一致。类型是File类型的

private String photoFileName;     //上传的文件名

private String photoContentType;  //上传文件的MIME类型(这里contentType和上传字段photo合作通过拦截器得到类型)

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public File getPhoto() {

return photo;

}

public void setPhoto(File photo) {

this.photo = photo;

}

public String getPhotoFileName() {

return photoFileName;

}

public void setPhotoFileName(String photoFileName) {

this.photoFileName = photoFileName;

}

public String getPhotoContentType() {

return photoContentType;

}

public void setPhotoContentType(String photoContentType) {

//System.out.println("调用getPhotoContentType方法"+photoContentType);

this.photoContentType = photoContentType;

}

@Override

public String toString() {

return "UploadAction1 [username=" + username + ", photo=" + photo + ", photoFileName=" + photoFileName + ", photoContentType=" + photoContentType + "]";

}

public String upload()

{

System.out.println(photoFileName+"(上传文件的名)"+photoContentType+"(上传文件的MIME类型)");

System.out.println(username);

//上传字段:上传到某个文件夹。存到应用的images目录下

String realPath = ServletActionContext.getServletContext().getRealPath("/files");

File file = new File(realPath);

if(!file.exists())

{

file.mkdirs();

}

try {

FileUtils.copyFile(photo, new File(file, photoFileName));

System.out.println(this.toString());

return SUCCESS;

} catch (IOException e) {

e.printStackTrace();

return ERROR;

}

}

}

3. 多文件上传于单文件上传的关系区别不是太大,关键是action类的编写:

uploadAction2.java文件的编写如下所示:

package com.itheima.action;

import java.io.File;

import java.io.IOException;

import org.apache.commons.io.FileUtils;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

//文件上传:fileUpload拦截器完成的

public class UploadAction2 extends ActionSupport {

private String username;

private File[] photo;//和表单的上传字段名保持一致。类型是File类型的 .数组或List

private String[] photoFileName;//上传的文件名

private String[] photoContentType;//上传文件的MIME类型

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public File[] getPhoto() {

return photo;

}

public void setPhoto(File[] photo) {

this.photo = photo;

}

public String[] getPhotoFileName() {

return photoFileName;

}

public void setPhotoFileName(String[] photoFileName) {

this.photoFileName = photoFileName;

}

public String[] getPhotoContentType() {

return photoContentType;

}

public void setPhotoContentType(String[] photoContentType) {

this.photoContentType = photoContentType;

}

public String upload(){

//上传字段:上传到某个文件夹。存到应用的images目录下

String realPath = ServletActionContext.getServletContext().getRealPath("/images");

File directory = new File(realPath);

if(!directory.exists()){

directory.mkdirs();

}

try {

for(int i=0;i<photo.length;i++){

FileUtils.copyFile(photo[i], new File(directory, photoFileName[i]));

}

return SUCCESS;

} catch (IOException e) {

e.printStackTrace();

return ERROR;

}

}

}

文件的下载

如下所示:下在一张指定位置的图片文件名为“女神张泓洋(22).jpg”

A.编写指定的Action类

package com.itheima.action;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.InputStream;

import java.net.URLEncoder;

import org.apache.commons.io.FilenameUtils;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class DownloadAction extends ActionSupport {

private InputStream image;//用in有问题的

private String filename;//文件名

private long filesize;

public InputStream getImage() {

return image;

}

public void setImage(InputStream image) {

this.image = image;

}

public String getFilename() {

return filename;

}

public long getFilesize() {

return filesize;

}

public String download() throws Exception{

//给image字节流赋值

String fileRealPath = ServletActionContext.getServletContext().getRealPath("/WEB-INF/classes/女神张泓洋 (22).jpg");

filename = FilenameUtils.getName(fileRealPath);

//方式一:中文文件要进行URL编码

//filename = URLEncoder.encode(filename, "UTF-8");

filesize = new File(fileRealPath).length();

System.out.println(filename);

image = new FileInputStream(fileRealPath);

return SUCCESS;

}

}

Struts.xml文件中的配置如下:

<constant name="struts.ognl.allowStaticMethodAccess" value="true" />

。。。。。。。。。ajijiiiaoj

<action name="download" class="com.itheima.actions.DownloadAction" method="download">

<result type="stream">

<param name="inputName">image</param>

<param name="contentType">application/octet-stream</param>

<!-- 在struts.xml中使用OGNL表达式获取动作类中属性的值。 调用动作类中的 getFilename()-->

<!-- 中文文件名编码:方式二.使用OGNL表达式,调用URLEncode的静态方法 -->

<!-- 默认OGNL调用静态方法是不行的,需要开启一个常量开关.struts.ognl.allowStaticMethodAccess=true -->

<param name="contentDisposition">attachment;filename=${@java.net.URLEncoder@encode(filename,'UTF-8')}</param>

<param name="contentLength">${filesize}</param>

</result>

</action>

strut2-学习笔记(二)的更多相关文章

  1. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  2. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  3. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  4. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  5. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  6. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  7. 《SQL必知必会》学习笔记二)

    <SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...

  8. NumPy学习笔记 二

    NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...

  9. Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  10. Redis学习笔记二 (BitMap算法分析与BitCount语法)

    Redis学习笔记二 一.BitMap是什么 就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身.我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省 ...

随机推荐

  1. js函数防抖、节流实现

    防抖 Debounce 函数防抖就是,延迟一段时间再执行函数,如果这段时间内又触发了该函数,则延迟重新计算: // 简单实现 function debounce(fn, wait) { let t r ...

  2. 汇编指令-adr与ldr伪汇编区别(8)

    adr :相对寻址,与当前位置有关 ldr  :绝对寻址,与当前位置无关 在初始化SDRAM时就会用到adr,代码如下: /* 初始化SDRAM */ ldr r0,=BWSCON //r0=SDRA ...

  3. 那些年,我们不懂的却又不得不提的 JAVA异常和异常处理!

    ---恢复内容开始--- 首先,我是个小小的菜鸟,最近突然突发奇想,想研究一下java的异常和异常的处理,稍有些理解,老鸟们莫要嘲笑... 既然要讲异常和异常的处理,我们就要先了解异常,那么,什么是异 ...

  4. 团队作业4——第一次项目冲刺(Alpha版本)3rd day

    一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 1.界面 界面已初步完成并能够进行简单的界面关联 界面内的功能正在完善 2.登陆方面 QQ授权已申请,等待通过 申请通过后在登 ...

  5. 201521123010 《Java程序设计》第8周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 本次作业题集集合 ①List中指定元素的删除(题目4-1) 1.1 实验总结 A: 这道题是老 ...

  6. 201521123051 《Java程序设计》 第二周学习总结

    1. 本周学习总结 1.学会使用码云:学会如何将项目同步到码云中以及从码云上的项目保存到本地. 2.各数据类型的使用. 3.运算符和表达式的使用. 4.string创建之后不可在修改. 5.Java程 ...

  7. 2017JAVA课程设计

    1.团队课程设计博客链接 http://www.cnblogs.com/ltykm/p/7063663.html 2.个人负责模块或任务说明 本人任务:定时器具体功能的实现 3.自己的代码提交记录截图 ...

  8. 12.Linux之输入子系统分析(详解)

    版权声明:本文为博主原创文章,转载请标注出处:   在此节之前,我们学的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥/非阻塞.定时 ...

  9. JavaEE error整理(不断更新)

    该文章用于整理开发中遇到的一些错误,及解决方法,不断整理更新. 1. 缺包异常 异常1:java.lang.NoClassDefFoundError: org/apache/commons/loggi ...

  10. Java NIO vs IO

    NIO :http://tutorials.jenkov.com/java-nio/index.html IO:http://tutorials.jenkov.com/java-io/index.ht ...