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. JavaScript封装一个MyAlert弹出框

    平时我们想要显示一些提示信息时会用到alert方法,alert是全局的一个方法,会短暂的中断程序,我们主要用来显示提示客户信息.但是这个方法有一定的局限性,而且本身样式也不够美观.于是我封装了一个实用 ...

  2. 团队作业4---第一次项目冲刺(ALpha版本)第一天

    一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 1.界面 完成登录界面 2.功能 完成数据结构设计及数据交互模块代码 完成爬虫博客页面数据采集模块 四.困难与问题 1.因为要 ...

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

    一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 界面 1.四个用户登录界面已经完成. 2.界面内的功能完成了一小部分. 登陆部分 1.QQ授权已经申请,还未通过. 2.通过好 ...

  4. 201521123057 《Java程序设计》 第7周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 答:源代码: pub ...

  5. 201521123008《Java程序设计》第1周学习总结

    本周学习总结 了解了JAVA:jdk:jre:jvm等 C语音与JAVA的部分区别: C语言全面向过程,java面向对象: C语言的代码不能跨平台,java的代码可以跨平台: C语言有指针,java没 ...

  6. 201521123086 《Java程序设计》第9周学习总结

    本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. (1)使用try...catch语句捕获异常(try块后可跟一个或多个catch块,注意子类异常要放在父类异常前面,否则子 ...

  7. 201521123054 《Java程序设计》第14周学习总结

    1. 本周学习总结 2. 书面作业 1. MySQL数据库基本操作 1.1建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己的学号.姓名) 1.2在自己建立的数据库上执行常见SQL语句 ...

  8. Map.containsKey方法——判断Map集合对象中是否包含指定的键名

    该方法判断Map集合对象中是否包含指定的键名.如果Map集合中包含指定的键名,则返回true,否则返回false. public static void main(String[] args) { M ...

  9. java继承涉及的动/静态绑定及隐藏

    项目中经常会用到java多态这个特性,之前只知道一些皮毛,现在发现自己对它并没有一个系统的认识,想从新梳理下自己的基础库. 看了java编程思想中对象导论,关于继承的描述:java中的类型不仅仅只是描 ...

  10. mybatis-basedao的实现

    package com.yangwei.shop.dao; import java.util.HashMap; import java.util.List; import java.util.Map; ...