前一阵子有些朋友在电子邮件中问关于Struts 2实现文件上传的问题, 所以今天我们就来讨论一下这个问题。
实现原理
Struts 2是通过Commons FileUpload文件上传。Commons FileUpload通过将HTTP的数据保存到临时文件夹,然后Struts使用fileUpload拦截器将文件绑定到Action的实例中。从而我们就能够以本地文件方式的操作浏览器上传的文件。
具体实现
前段时间Apache发布了Struts 2.0.6 GA,所以本文的实现是以该版本的Struts作为框架的。以下是例子所依赖类包的列表:
清单1 依赖类包的列表
首先,创建文件上传页面FileUpload.jsp,内容如下:
<% @ page language = " java " contentType = " text/html; charset=utf-8 " pageEncoding = " utf-8 " %>
<% @ taglib prefix = " s " uri = " /struts-tags " %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > Struts 2 File Upload </ title >
</ head >
< body >
< s:form action ="fileUpload" method ="POST" enctype ="multipart/form-data" >
< s:file name ="myFile" label ="Image File" />
< s:textfield name ="caption" label ="Caption" />
< s:submit />
</ s:form >
</ body >
</ html > 清单2 FileUpload.jsp
在FileUpload.jsp中,先将表单的提交方式设为POST,然后将enctype设为multipart/form-data,这并没有什么特别之处。接下来,<s:file/>标志将文件上传控件绑定到Action的myFile属性。
其次是FileUploadAction.java代码:
package tutorial;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class FileUploadAction extends ActionSupport {
private static final long serialVersionUID = 572146812454l ;
private static final int BUFFER_SIZE = 16 * 1024 ;
private File myFile;
private String contentType;
private String fileName;
private String imageFileName;
private String caption;
public void setMyFileContentType(String contentType) {
this .contentType = contentType;
}
public void setMyFileFileName(String fileName) {
this .fileName = fileName;
}
public void setMyFile(File myFile) {
this .myFile = myFile;
}
public String getImageFileName() {
return imageFileName;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this .caption = caption;
}
private static void copy(File src, File dst) {
try {
InputStream in = null ;
OutputStream out = null ;
try {
in = new BufferedInputStream( new FileInputStream(src), BUFFER_SIZE);
out = new BufferedOutputStream( new FileOutputStream(dst), BUFFER_SIZE);
byte [] buffer = new byte [BUFFER_SIZE];
while (in.read(buffer) > 0 ) {
out.write(buffer);
}
} finally {
if ( null != in) {
in.close();
}
if ( null != out) {
out.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getExtention(String fileName) {
int pos = fileName.lastIndexOf( " . " );
return fileName.substring(pos);
}
@Override
public String execute() {
imageFileName = new Date().getTime() + getExtention(fileName);
File imageFile = new File(ServletActionContext.getServletContext().getRealPath( " /UploadImages " ) + " / " + imageFileName);
copy(myFile, imageFile);
return SUCCESS;
}
} 清单3 tutorial/FileUploadAction.java
在FileUploadAction中我分别写了setMyFileContentType、setMyFileFileName、setMyFile和setCaption四个Setter方法,后两者很容易明白,分别对应FileUpload.jsp中的<s:file/>和<s:textfield/>标志。但是前两者并没有显式地与任何的页面标志绑定,那么它们的值又是从何而来的呢?其实,<s:file/>标志不仅仅是绑定到myFile,还有myFileContentType(上传文件的MIME类型)和myFileFileName(上传文件的文件名,该文件名不包括文件的路径)。因此,<s:file name="xxx" />对应Action类里面的xxx、xxxContentType和xxxFileName三个属性。
FileUploadAction作用是将浏览器上传的文件拷贝到WEB应用程序的UploadImages文件夹下,新文件的名称是由系统时间与上传文件的后缀组成,该名称将被赋给imageFileName属性,以便上传成功的跳转页面使用。
下面我们就来看看上传成功的页面:
<% @ page language = " java " contentType = " text/html; charset=utf-8 " pageEncoding = " utf-8 " %>
<% @ taglib prefix = " s " uri = " /struts-tags " %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > Struts 2 File Upload </ title >
</ head >
< body >
< div style ="padding: 3px; border: solid 1px #cccccc; text-align: center" >
< img src ='UploadImages/<s:property value ="imageFileName" /> ' />
< br />
< s:property value ="caption" />
</ div >
</ body >
</ html > 清单4 ShowUpload.jsp
ShowUpload.jsp获得imageFileName,将其UploadImages组成URL,从而将上传的图像显示出来。
然后是Action的配置文件:
<? xml version="1.0" encoding="UTF-8" ?>
<! DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd" >
< struts >
< package name ="fileUploadDemo" extends ="struts-default" >
< action name ="fileUpload" class ="tutorial.FileUploadAction" >
< interceptor-ref name ="fileUploadStack" />
< result name ="success" > /ShowUpload.jsp </ result >
</ action >
</ package >
</ struts > 清单5 struts.xml
fileUpload Action显式地应用fileUploadStack的拦截器。
最后是web.xml配置文件:
<? xml version="1.0" encoding="UTF-8" ?>
< web-app id ="WebApp_9" version ="2.4"
xmlns ="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
< display-name > Struts 2 Fileupload </ display-name >
< filter >
< filter-name > struts-cleanup </ filter-name >
< filter-class >
org.apache.struts2.dispatcher.ActionContextCleanUp
</ filter-class >
</ filter >
< filter >
< filter-name > struts2 </ filter-name >
< filter-class >
org.apache.struts2.dispatcher.FilterDispatcher
</ filter-class >
</ filter >
< filter-mapping >
< filter-name > struts-cleanup </ filter-name >
< url-pattern > /* </ url-pattern >
</ filter-mapping >
< filter-mapping >
< filter-name > struts2 </ filter-name >
< url-pattern > /* </ url-pattern >
</ filter-mapping >
< welcome-file-list >
< welcome-file > index.html </ welcome-file >
</ welcome-file-list >
</ web-app > 清单6 WEB-INF/web.xml
发布运行应用程序,在浏览器地址栏中键入:http://localhost:8080/Struts2_Fileupload/FileUpload.jsp,出现图示页面:
清单7 FileUpload页面
选择图片文件,填写Caption并按下Submit按钮提交,出现图示页面:
清单8 上传成功页面
更多配置
在运行上述例子,如果您留心一点的话,应该会发现服务器控制台有如下输出:
Mar 20 , 2007 4 : 08 : 43 PM org.apache.struts2.dispatcher.Dispatcher getSaveDir
INFO: Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
Mar 20 , 2007 4 : 08 : 43 PM org.apache.struts2.interceptor.FileUploadInterceptor intercept
INFO: Removing file myFile C:/Program Files/Tomcat 5.5 /work/Catalina/localhost/Struts2_Fileupload/upload_251447c2_1116e355841__7ff7_00000006.tmp 清单9 服务器控制台输出
上述信息告诉我们,struts.multipart.saveDir没有配置。struts.multipart.saveDir用于指定存放临时文件的文件夹,该配置写在struts.properties文件中。例如,如果在struts.properties文件加入如下代码:
struts.multipart.saveDir = /tmp 清单10 struts配置
这样上传的文件就会临时保存到你根目录下的tmp文件夹中(一般为c:/tmp),如果此文件夹不存在,Struts 2会自动创建一个。
错误处理
上述例子实现的图片上传的功能,所以应该阻止用户上传非图片类型的文件。在Struts 2中如何实现这点呢?其实这也很简单,对上述例子作如下修改即可。
首先修改FileUpload.jsp,在<body>与<s:form>之间加入“<s:fielderror />”,用于在页面上输出错误信息。
然后修改struts.xml文件,将Action fileUpload的定义改为如下所示:
< action name ="fileUpload" class ="tutorial.FileUploadAction" >
< interceptor-ref name ="fileUpload" >
< param name ="allowedTypes" >
image/bmp,image/png,image/gif,image/jpeg
</ param >
</ interceptor-ref >
< interceptor-ref name ="defaultStack" />
< result name ="input" > /FileUpload.jsp </ result >
< result name ="success" > /ShowUpload.jsp </ result >
</ action > 清单11 修改后的配置文件
显而易见,起作用就是fileUpload拦截器的allowTypes参数。另外,配置还引入defaultStack它会帮我们添加验证等功能,所以在出错之后会跳转到名称为“input”的结果,也即是FileUpload.jsp。
发布运行应用程序,出错时,页面如下图所示:
清单12 出错提示页面
上面的出错提示是Struts 2默认的,大多数情况下,我们都需要自定义和国际化这些信息。通过在全局的国际资源文件中加入“struts.messages.error.content.type.not.allowed=The file you uploaded is not a image”,可以实现以上提及的需求。对此有疑问的朋友可以参考我之前的文章《在Struts 2.0中国际化(i18n)您的应用程序》。
实现之后的出错页面如下图所示:
清单13 自定义出错提示页面
同样的做法,你可以使用参数“maximumSize”来限制上传文件的大小,它对应的字符资源名为:“struts.messages.error.file.too.large”。
字符资源“struts.messages.error.uploading”用提示一般的上传出错信息。
多文件上传
与单文件上传相似,Struts 2实现多文件上传也很简单。你可以将多个<s:file />绑定Action的数组或列表。如下例所示。
< s:form action ="doMultipleUploadUsingList" method ="POST" enctype ="multipart/form-data" >
< s:file label ="File (1)" name ="upload" />
< s:file label ="File (2)" name ="upload" />
< s:file label ="FIle (3)" name ="upload" />
< s:submit />
</ s:form > 清单14 多文件上传JSP代码片段
如果你希望绑定到数组,Action的代码应类似:
private File[] uploads;
private String[] uploadFileNames;
private String[] uploadContentTypes;
public File[] getUpload() { return this .uploads; }
public void setUpload(File[] upload) { this .uploads = upload; }
public String[] getUploadFileName() { return this .uploadFileNames; }
public void setUploadFileName(String[] uploadFileName) { this .uploadFileNames = uploadFileName; }
public String[] getUploadContentType() { return this .uploadContentTypes; }
public void setUploadContentType(String[] uploadContentType) { this .uploadContentTypes = uploadContentType; } 清单15 多文件上传数组绑定Action代码片段
如果你想绑定到列表,则应类似:
private List < File > uploads = new ArrayList < File > ();
private List < String > uploadFileNames = new ArrayList < String > ();
private List < String > uploadContentTypes = new ArrayList < String > ();
public List < File > getUpload() {
return this .uploads;
}
public void setUpload(List < File > uploads) {
this .uploads = uploads;
}
public List < String > getUploadFileName() {
return this .uploadFileNames;
}
public void setUploadFileName(List < String > uploadFileNames) {
this .uploadFileNames = uploadFileNames;
}
public List < String > getUploadContentType() {
return this .uploadContentTypes;
}
public void setUploadContentType(List < String > contentTypes) {
this .uploadContentTypes = contentTypes;
} 清单16 多文件上传列表绑定Action代码片段
总结
在Struts 2中实现文件上传的确是轻而易举,您要做的只是使用<s:file />与Action的属性绑定。这又一次有力地证明了Struts 2的简单易用。
struts2文件上传与下载(1)
struts学习 2009-07-18 09:51 阅读51 评论0 字号: 大大 中中 小小 其实这节的内容没有任何struts2的内容.只是介绍只用html来实现文件的上传.之所以要写这个,就是能理解一些底层的实现
只写两个页面...
upload.jsp
<body>
<form action="result.jsp" method="post" enctype="multipart/form-data"> //注意,这里默认是enctype="application/x-www-form-urlencoded".也就是字符串类型.必须转换成这个..还有.method必须是"post".这两点特别注意
Information: <input type="text" name="info"><br>
File: <input type="file" name="file"><br>
<input type="submit" name="submit" value=" submit ">
</form> //其他都没什么不一样..
</body>
result.jsp
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ page import="java.io.*" %>
<!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=GB18030">
<title>Insert title here</title>
</head>
<body>
<% //都是java代码..直接写页面上不行...不过我们只是为了演示...就算了.
InputStream is = request.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String buffer = null;
while((buffer = br.readLine()) != null)
{
out.print(buffer + "<br>");
}
%>
</body>
</html>
struts2文件上传与下载(2)
struts学习 2009-07-18 20:20 阅读80 评论0 字号: 大大 中中 小小 本节还是不用struts2的内容实现文件的上传...不过这节的内容实现了文件彻底意义上的上传(上一节是通过读字符流的方式将文本文件的内容读出来并显示)..这节是讲文件复制到我们需要的地方(其实就是我们一般意义上的上传)
这里,我们不需要用struts的过滤器(其实就是不需要用struts了.因为我们在web.xml上面定义的struts过滤器,我们这里要将它注释掉,然后自己写servlet)...
首先,还是先将两个页面放上来..
upload2.jsp 注意,这里我将这两个jsp文件都放到upload文件夹下面了...所以一些目录代码会有些修改
.<body>
<form action="/struts2/UploadServlet" method="post" enctype="multipart/form-data"> //再次强调,这里的method必须是post.还有enctype也必须改成这个. 这里的action为什么是这个.看下面我设置servlet的就明白了..
fname:<input type="text" name="name" ><br>
password:<input type="password" name="password"><br>
file1:<input type="file" name="file1"><br>
file2:<input type="file" name="file2"><br>
<input type="submit">
</form>
result2.jsp //到时候我会设置servlet跳转到这个页面.所以不用着急
<body>
name:<%=request.getAttribute("name") %><br>//到时候我会把这个字段的内容放到attribute里面..
password:${requestScope.password }<br>
file1:${requestScope.file1 }<br>
file2:${requestScope.file2 }
</body>
2 创建自己的servlet.这里是关键 ..
package com.test.servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { //因为我们是用post方法传进来的.所以只需要实现doPost方法
DiskFileItemFactory factory = new DiskFileItemFactory(); //创建一个factory
String path="D://file"; //这里是上传文件存放的路径.注意这里的反斜杠要两个/
factory.setRepository(new File(path));//factory中注入文件名称
factory.setSizeThreshold(1024*1024);//注入文件限制大小
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> list = upload.parseRequest(request);//将传入的request内容封装成一个list对象
for(FileItem item : list)//对象循环..每一个item对应一个对象.比如name 是一个对象 file1也是一个对象
{
if(item.isFormField()) //判断是否为文件对象..也就是说.如果这个对象是文件的话返回假..否则返回真
{
String color=#ff0000>//获取这个name属性.对应页面里的那个 value = item.getString("GBK"); //获取对应的value,也就是说我们输入的这个值.
request.setAttribute(name, value);//注入到attribute中
System.out.println(value);
} else
{
String name = item.getFieldName();//同理,这里是file1 和 file2
String value = item.getName(); //注意,这里是getName.而不是上面的getString .这个是根据浏览器的不同,会返回文件的名字或者路径..比如 C:/aaa.txt..有的浏览器就返回aaa.txt.而有的浏览器就返回C:/aaa.txt.所以下面进行了统一
int start = value.lastIndexOf("//");//获取最后一个反斜杠的位置.
String fieldName = value.substring(start+1);//最后一个反斜杠的位置后面的那串字符串就是我们的文件名.
System.out.println(name);
request.setAttribute(name, fieldName);
try {
item.write(new File(path,fieldName)); //注意,这里提供了一个item对象的write方法..其实也就是将上传的文件放到path路径代表的地方,另存为的文件名是fieldName
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//下面注释的部分就是不用write方法自己复制字节流的办法
// OutputStream out = new FileOutputStream(new File(path,fieldName));
// InputStream is = item.getInputStream();
// int length = 0;
// byte[] b = new byte[400];
// while ((length = is.read(b)) > 0)
// {
// out.write(b);
// }
// out.close();
// is.close();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
request.getRequestDispatcher("/upload/result2.jsp").forward(request, response);//将页面跳转到result2.jsp.
}
}
3 修改web.xml...直接将代码贴上来了.蛮容易的.注意看,那个strut2的filter被我注释掉了..
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!--
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.test.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/UploadServlet</url-pattern>
</servlet-mapping>
</web-app>
至此,整个工程就结束了.当然一定要导入两个包,一个是common-fileupload.jar.还有一个是common-io.jar ..
我们之所以要说这些和struts无关的东西就是为了能了解struts2关于文件上传的底层实现..其实,strut2就是这么实现文件上传的.
struts2文件上传与下载(3)
struts学习 2009-07-20 10:06 阅读158 评论0 字号: 大大 中中 小小 这里,我们终于要用strust2自带的文件上传系统来做我们自己的文件上传了....
首先,当然是写页面了..
upload.jsp 这个在webroot下面的upload文件夹下...没啥可说的.就是一个html
<body>
<form action="upload.action" method="post" enctype="multipart/form-data">
Information: <input type="text" name="info"><br>
File: <input type="file" name="file"><br>
<input type="submit" name="submit" value=" submit ">
</form>
</body>
result.jsp 这里记得加strust2标签引入...
<body><br>
info:<s:property value="info"/><br>
filename:<s:property value="fileFileName"/>
</body>
2 写action的java文件 upload.java
这里比较长.我一个个解释
package com.test.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import com.opensymphony.xwork2.ActionSupport;
public class upload extends ActionSupport {
private String info;
private File file ; // 这里对应的jsp页面上的两个字段.没啥可以说.
private String fileFileName;//注意,这个表示的是file这个上传对象的文件名..这个是struts2自己封装的.可以自动获取,不用和上一节一样需要我们自己去写代码.. 这里的名字后面部分"FileName"是固定的,前面的file就是上面那个file.也就是说和jsp页面的那个字段的name是对应的..
private String fileContentType;//这里也同样,表示文件类型.struts2已经封装好的.后面的"ContentType"也是固定的.
public String getInfo() { //下面大部分都是get,set方法,没啥好说的.都是自动生成的.
return info;
}
public void setInfo(String info) {
this.info = info;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getFileFileName() {
return fileFileName;
}
public void setFileFileName(String fileFileName) {
this.fileFileName = fileFileName;
}
public String getFileContentType() {
return fileContentType;
}
public void setFileContentType(String fileContentType) {
this.fileContentType = fileContentType;
}
@Override
public String execute() throws Exception {
//重头戏从这里开始
InputStream is = new FileInputStream(file); //定义一个输入流..file对应上面的上传文件对象.
String root = "D://file";//这里先定义一个文件上传的目录...就是将上传的文件放到D盘的file文件下面.
File diskfile = new File(root,this.getFileFileName());//定义输出流存放的文件夹..文件名为getFileFileName .也就是说,是和上传的文件相同.
OutputStream os = new FileOutputStream(diskfile);//定义一个输出流..对应输出的文件夹
byte[] buffer = new byte[400];//这里和之前的上传与下载第一节里的内容一样.不多解释了..
int length = 0;
while((length = is.read(buffer))>0)
{
os.write(buffer);
}
is.close();
os.close();
return SUCCESS;
}
}
3.最后就是strut.xml配置文件了
注意,我为了避免干扰,讲拦截器都注释掉了...
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.i18n.encoding" value="gbk"></constant>//这里定义一个编码方式是用gbk.这样你传文件的时候就可以用中文的文件名.要不然就出乱码
<constant value="d:/"></constant>//这里定义的是临时目录..文件上传的时候会先将文件复制到临时目录,然后将临时目录里的文件用IO的方式上传.
<constant value="message"></constant>
<package name="struts2" extends="struts-default">
<interceptors>
<interceptor name="myInterceptor" class="com.test.interceptor2.MyInterceptor">
<param name="hello">world</param>
</interceptor>
<interceptor name="myInterceptor2" class="com.test.interceptor2.MyInterceptor2">
</interceptor>
<interceptor name="myInterceptor3" class="com.test.interceptor2.MyInterceptor3">
</interceptor>
<interceptor-stack name="myStack">
<!--
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="myInterceptor2"></interceptor-ref>
-->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<action name="login" class="com.test.action.LoginAction">
<result name="input">/login2.jsp</result>
<result name="success">/result.jsp</result>
<result name="failer">/login2.jsp</result>
</action>
<action name="pointConverter" class="com.test.action.PointAction">
<result name="success">/output.jsp</result>
<result name="input">/input.jsp</result>
</action>
<action name="upload" class="com.test.action.upload">
<result>/upload/result.jsp</result>
</action>
<action name="register" class="com.test.action.RegisterAction" method="test">
<result name="success">/success.jsp</result>
<result name="input">/register2.jsp</result>
<!--
<interceptor-ref name="myInterceptor3">
<param name="excludeMethods">test,execute</param>
<param name="includeMethods">test</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
-->
</action>
</package>
</struts>
其他没可以说的.这样,我们的文件上传就已经实现了..
注意,要注入common-io.jar和common-fileupload.jar..
struts2上传与下载(4)多文件上传
struts学习 2009-07-20 13:56 阅读64 评论0 字号: 大大 中中 小小 上一节,我们完成了单个文件的上传.但是,很明显,实际应用里面,我们必须完成多文件的上传.
首先,我们先完成固定个数的多文件上传
我们修改JSP页面
upload.jsp
<body>
<form action="upload.aciton" method="post" enctype="multipart/form-data">
Information:<input type="text" name="info"><br>
file1:<input type="file" name="file"><br>
file2:<input type="file" name="file"><br>
file3:<input type="file" name="file"><br>//注意,这里的name属性都是file.这样表单提交会是一个file类型的数组
</body>
很明显,action也需要修改...
注意,其实action就修改了两个地方..一个是File类型的file变成了List<File> file 这样系统会自动给我们返回一个List数组..修改相应的get,set方法.第二个修改的地方是 execute方法里.读IO的时候进行了一个for循环.这个也不难看懂..
package com.test.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
public class upload extends ActionSupport {
private String info;
private List<File> file ;
private List<String> fileFileName;
private List<String> fileContentType;
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public List<File> getFile() {
return file;
}
public void setFile(List<File> file) {
this.file = file;
}
public List<String> getFileFileName() {
return fileFileName;
}
public void setFileFileName(List<String> fileFileName) {
this.fileFileName = fileFileName;
}
public List<String> getFileContentType() {
return fileContentType;
}
public void setFileContentType(List<String> fileContentType) {
this.fileContentType = fileContentType;
}
@Override
public String execute() throws Exception {
for(int i=0;i<file.size();i++)
{
InputStream is = new FileInputStream(file.get(i));
String root = "D://file";
File diskfile = new File(root,this.getFileFileName().get(i));
OutputStream os = new FileOutputStream(diskfile);
byte[] buffer = new byte[400];
int length = 0;
while((length = is.read(buffer))>0)
{
os.write(buffer);
}
is.close();
os.close();
}
return SUCCESS;
}
}
这样.这个多文件上传就做好了..还是很简单的...
现在,我们还有一个需求,我们需要动态改变上传文件的个数..其实这个也很好了解..一般用过邮箱的人都知道.系统开始会给你一个上传文件的地方.然后你可以点按钮动态添加上传的个数..我们现在就来做这个东西...
其实,这个和struts也没多大关系了..因为这个只需要修改jsp页面.而后台所有的代码都不需要修改..页面如下
upload.jsp
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<!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=GB18030">
<title>Insert title here</title>
<script type="text/javascript">
function add()
{
var td = document.getElementById("more");
var br = document.createElement("br");
var file = document.createElement("input");
var remove = document.createElement("input");
file.type="file";
file.name="file";
remove.type="button";
remove.value="remove";
remove.onclick=function()
{
td.removeChild(br);
td.removeChild(file);
td.removeChild(remove);
}
td.appendChild(br);
td.appendChild(file);
td.appendChild(remove);
}
</script>
</head>
<body>
<form action="upload.action" method="post" enctype="multipart/form-data">
<table align="center" >
<tr>
<td>Information:</td><td> <input type="text" name="info"></td><td></td>
</tr>
<tr>
<td>File: </td><td id="more"> <input type="file" name="file"><input type="button" value="add more.." onclick="add()"></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" name="submit" value=" submit "></td>
</tr>
</table>
</form>
</body>
</html>
这样,我们所有的工作都已经完成.其实这个说到底就是一个用javascript在客户端动态修改html..我们可以添加file或者删除file...其中的name属性还是file...很简单,不是么
struts文件上传与下载(5)文件大小和类型设置
struts学习 2009-07-20 17:08 阅读82 评论0 字号: 大大 中中 小小 这节说的struts框架对文件上传的大小和类型设置.
首先,我们必须明白,struts的文件上传是通过拦截器来实现的.我们可以找到对也难怪的拦截器包..在strut2-core.jar包里面有一个struts-default.xml这个文件.我们写的struts.xml都是继承这个配置文件的.而在struts-default.xml里面有一个interceptor..叫做fileUpload..这个就是上传的拦截器..对应的class为struts-core.jar下面的org.apache.struts2.interceptor包下面有一个FileUploadInterceptor..里面可以注意两个参数.maximumSize和allowedTypes.很明显.这两个分别对应上传文件大小和类型...说到这里,我们就应该明白怎么设置了吧..我们就是在拦截器定义参数.并将参数传进去.这样子就OK了..
如下
<action name="upload" class="com.test.action.upload">
<result>/upload/result.jsp</result>
<result name="input">/upload/upload.jsp</result>
<interceptor-ref name="fileUpload">
<param name="maximumSize">409600</param>
<param name="allowedTypes">text/plain</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>注意,这里要将默认拦截器加上.什么原因,不说了
</action>
这里,我们注意在设置 类型的时候,后面的参数是 text/plain ..我们怎么知道这个参数是什么呢..我们可以看tomcat目录下面的conf下的web.xml 比如我的D:/apache-tomcat-6.0.14/apache-tomcat-6.0.14/conf.下的web.xml..里面有类型定义..比如
<mime-mapping>
<extension>mp3</extension>
<mime-type>audio/x-mpeg</mime-type>
</mime-mapping>
这里就说明.后缀是mp3的对应的是audio/x-mpeg 具体用到什么就是什么....
做到这里,我们需要的基本需求已经差不多完成了..运行之后,我们会发现,如果上传文件的类型或者大小不符合要求的话.他会自动返回一个Input.然后跳转回upload.jsp...注意,这里还会自动执行addFiledError.并添加相应的错误信息..当然,错误信息的内容我们也可以修改...可以再strut2-core.jar包下面的org.apache.struts2下面找到一个struts-messages.properties文件.这里有系统默认的提示信息..我们可以修改相应的信息..在哪修改呢...还记得以前我们定义的message.properties么...我们就是进行全局修改...在message.properties下面添加
struts.messages.error.content.type.not.allowed=/u4e0a/u4f20/u6587/u4ef6/u7c7b/u578b/u9519/u8bef
这样,类型错误的信息就会提示..后面是中文 "类型转换错误"的编码..通过jdk自带的 native2ascii 命令得到的..以前说过了,不具体说...
所有的一切都OK了.记得在JSP页面上加上<s:fielderror></s:fielderror> .这样,如果错误的话,相应的错误信息就会显示出来了...
struts2上传与下载(6) 下载
struts学习 2009-07-21 10:16 阅读63 评论0 字号: 大大 中中 小小 下载部分相应来说比较简单...只要返回一个InputStream就OK...具体的做法.
页面..
download.jsp 超级简单.就是一个<a>标签.链接到download.action
<body>
<a href="download.action">download</a>
</body>
action
DownloadAction.java
package com.test.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class DownloadAction extends ActionSupport {
public InputStream getDownloadFile() throws FileNotFoundException
{//这里定义这个get方法是因为在struts.xml配置文件里要设置一个downloadFile(这里注意javabean的规范.D字从大写变回小写)这个参数.返回值是一个inputStream
System.out.println("gose here");
File file = new File("d://Struts2.ppt");
InputStream in = new FileInputStream(file);//这里的InputStream是一个File类型的..
return in;
//return ServletActionContext.getServletContext().getResourceAsStream("/upload/Struts2.ppt");//这里是获取当前目录下的文件返回InputStream.
}
public String execute(){
return SUCCESS;
}
}
配置文件struts.xml
<action name="download" class="com.test.action.DownloadAction">
<result type="stream">//注意,这里的类型是流类型.对应的类可以到struts-default.xml下面看
<param >application/powerpoint</param>//这里是下载文件的类型.这里是PPT文件.默认是txt.参数的名字在上一节已经说了,可以在tomcat的conf下面的web.xml里面查找.
<param >filename="aaa.ppt"</param>//这里是文件另存为的名字
<param >downloadFile</param>//注意,这里这个参数就是对应action里面我们写的get方法
</result>
</action>
最最简单的文件下载.就是这样了..很简单了.呵呵
struts2相关内容的补充(1)
struts学习 2009-07-21 16:09 阅读26 评论0 字号: 大大 中中 小小 我们必须知道两个非常重要的配置文件.一个是default.properties 一个是struts-default.xml .下面来分别说
default.properties在struts-core.jar包里的org.apache.struts2里面..他是一个属性文件,对应nama和value 其中几个name我们必须要注意
struts.i18n.encoding=UTF-8 系统默认的编码方式就是在这里定义的..我们可以修改为GBK.方法后面会说.
struts.multipart.saveDir= 这个没定义.是上传文件的临时文件存放目录..如果你指定,系统会报一个临时目录不存在的警告,不过他还是会给你自动配一个的.在tomcat里面...
struts.multipart.maxSize=2097152 这个很好理解.就是上传文件的大小限制.2M的大小.记得这里的单位是字节
struts.action.extension=action,, 这个是struts2的默认后缀名修改.你可以改成abc..只要相应的jsp页面里也修改就行
暂时我知道的就这么些了,以后有用到再补吧.
这里开始说配置这些属性的办法.很明显,default.properties是只读的.不许修改.我们有三种办法可以修改它..
第一,也是最不常用的办法.在web.xml里面..比如这样
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<init-param>
<param-name>struts.i18n.encoding</param-name>在核心的控制器里进行初始化..配置一个属性就得四行代码.怎么都说不过去..虽然优先级最高,但是一般是不用的.
<param-value>gbk</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第二,在struts.xml里面配置...还记得以前我们配置编码方式不..就这样
<constant name="struts.i18n.encoding" value="gbk"></constant>
<constant name="struts.multipart.saveDir" value="d:/"></constant>
第三,在scr目录新建一个struts.properties文件...里面就是按照属性文件的方式来写..就是这样
struts.i18n.encoding = gbk
一般推荐使用第三种.
下面说下 struts-default.xml ..这个xml文件就在struts-core.jar包里.他是一个抽象包.也就是说,不能定义action.只能由继承他的xml文件才能定义action.比如我们之前一直用的struts.xml..
在struts.xml里面还有一点要说明下.就是命名空间的.问题..一般大的项目都会进行命名空间分配.这里就用到一个namespace..比如
<package name="struts2" extends="struts-default" namespace="hello">
这里,将命名空间指定为hello.假设这个package里面有一个action name为login.这样的话我们页面如果写成
<form action="login.action"> 将无法找到这个action.我们需要写成
<form action="/hello/login.action">
这里还注意一个问题..我们在用struts自带的标签的时候,我们写form action是不需要加后缀".action"的,但是加入命名空间以后我们就必须加.action..
最后,我们可以在struts.xml里面include其他的xml文件.这些配置文件就是为了减少struts.xml的代码量用的..这个很好理解.不多说了.
struts2相关内容补充(2)表单重复提交处理
struts学习 2009-07-22 14:19 阅读34 评论0 字号: 大大 中中 小小 很实用的功能..struts2处理非常简单.
1.首先在jsp的form标签下面加这个标签.就像这样
<s:form action="register" >
<s:token></s:token>
我们可以看到.这里会创建一个32的加密的value值.通过这个值来判断是否重复提交
2 配置文件修改..需要在对应的action申明里面添加token拦截器.如下
<action name="register" class="com.test.action.RegisterAction" >
<result name="success">/success.jsp</result>
<result name="input">/register2.jsp</result>
<result name="invalid.token">/register2.jsp</result>
<interceptor-ref ></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
3 在配置文件里添加一个result.对面的name为invalid.token..可以上上面那段代码.已经添加好了.
这里是因为,如果struts发现我们的操作是重复表单提交的话,会返回一个result .名字为 invalid.token .所以我们需要添加一个对应的处理..
注意,这里其实就是一个验证.如果验证错误的话就会返回一个invalid.token.当然他也会自动产生一个错误信息..默认可以看struts2-core.jar包下面的struts-message.properties.里面有一个
struts.messages.invalid.token=The form has already been processed or no token was supplied, please try again.
这个就是重复提交的默认错误提示.我们可以重写..以前已经说了.不具体说了.
最后说明下.这个错误信息是添加到addActionError里的.所以如果要在页面上显示的话需要添加标签
<s:actionerror/>
struts2整合spring
struts学习 2009-07-23 10:39 阅读233 评论5 字号: 大大 中中 小小 spring的作用.之前也说明了很多.其实就是IoC和AOP...很多人都说,spring就是玩配置文件....其实,spring最大的作用就是为了减少类之间的耦合.平时使用两个类,调用的时候难免会发生耦合.但是又不能没有一点耦合.那这两个类将一点关系都没有..spring的解决办法就是IoC.叫依赖注入...比如.类A要调用类B里的办法..怎么解决呢.我们以前的办法就是类A主动去调用类B.但是spring给出的办法是需要的时候给你...而且这个地方是通过配置文件来实现的.也就是说,是配置文件来给你.
开始之前,首先要说明一点,在struts的流程里有一步是struts.xml以后根据action name来调用对应的action类..我们之前的struts实现办法是自动生成一个action实例..是struts自动通过自带的factory来实现的..但是,我们这里需要用spring来帮我们生产action实例.当然,action里面调用的方法也通过spring来注入.
第一步,当然是导入相应的jar包.将struts2下载里面的struts2-spring-plugin.jar放入lib下..然后通过myeclipse导入spring..具体的办法是在相应的工程目录,右键,Myeclipse -->Add Spring Capabilities.然后在对话框里面.Spring 2.0 Core 打钩(这个默认已经打钩了),还有Spring 2.0 Web 打钩,因为我们需要用到里面的一个Listener.下面选择Copy checked Library contents.....如下图
然后就一直下一步.不需要修改了..
第二步.配置web.xml..因为我们需要通过spring来生成action实例..(也就是说.告诉struts ,spring的存在)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener >
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
第三步,写两个jsp页面测试.很简单,一个登陆页面,一个结果页面
login2.jsp
<s:form action="login" >
<s:textfield name="username" label="username"></s:textfield>
<s:password name="password" label="password"></s:password>
<s:submit ></s:submit>
</s:form>
result.jsp
<body>
username:<%=request.getParameter("username") %>
password:<%=request.getParameter("password") %>
</body>
两个都很简单,不多说了
第四步.写个业务处理类.包括一个接口,一个实现类..两个java文件
我们以前写的例子都是将业务代码放到action里面.很明显,这样做是不好的..我们需要将业务代码分离出来.而action只需要调用..
接口类LoginService.java 就定义了一个方法.返回一个布尔值
package com.test.service;
public interface LoginService {
public boolean isLogin(String username,String password);
}
实现类 LoginServiceImpl.java 实现类..假如username为hello.password为world的时候返回真..其他都为假
package com.test.serviceImpl;
import com.test.service.LoginService;
public class LoginServiceImp implements LoginService {
@Override
public boolean isLogin(String username, String password) {
if("hello".equals(username)&&"world".equals(password))
{
return true;
}
else
{
return false;
}
}
}
第五步,当然是写我们的action...LoginAction.java
package com.test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.test.service.LoginService;
public class LoginAction extends ActionSupport {
private String username;
private String password;
private LoginService loginService;//这里引入了一个LoginService.但是没有实例化.(如果在这里实例化,那就不用spring了...我们就是靠spring来注入这个loginService)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setLoginService(LoginService loginService) {//注意这里需要定义一个set方法.因为spring需要调用这个set方法
this.loginService = loginService;
}
public String execute() throws Exception{
if(loginService.isLogin(username, password))
{
return SUCCESS;//注意,这里只有调用的代码,没有业务逻辑代码了
}
else {
return INPUT;
}
}
第六步..配置struts.xml
<action name="login" class="loginAction">//注意,这里的class已经不是和以前那样的一个类的全名.而是一个自定义的名字.这个名字对应到了等下我们将要配置的applicationContext.xml(也就是spring的配置文件)里定义的bean Id ..
<result name="input">/login2.jsp</result>
<result name="success">/result.jsp</result>
</action>
第七步,applicationContext.xml spring的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="loginservice" class="com.test.serviceImpl.LoginServiceImp"></bean>//这里定义了一个loginservice的组件.对应业务逻辑的实现类
<bean id="loginAction" class="com.test.action.LoginAction" scope="prototype">//定义action.scope="prototype 表示请求一次,实例化一次
<property name="loginservice">
<ref local="loginservice"/>//将这个业务逻辑的实现类注入...
</property>
</bean>
</beans>
第八步..差不多都弄好了..不过需要将applicationContext.xml移到WEB-INF下面.测试,应该OK了
如果你不想把这个applicationContext.xml放到web-inf下..你可以在web.xml里面指定对应的存放地址.甚至可以写多个配置文件 ..方法是
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value>
</context-param>
上面这个是官方网站上拉来的代码..很容易懂.不多说了...注意对应的目录
SSH框架的第一个整合例子
SSH框架整合 2009-07-25 11:28 阅读27 评论0 字号: 大大 中中 小小 ,我们先实现一个最基本的需求..添加,然后保存以后返回列表页面.这里先不包括验证什么的..都假设输入是正确的.验证到下一节说明..
我们从需求出发...一步步实现.我这里用的是myeclipse6.0 .struts2.0.16.spring2.0 hibernate3 mysql5.1
1.准备工作...当然是数据库了..在mysql数据库里,创建一个名为"user"的数据库.创建一个表也叫"user". 表里面就三个字段,id ,username ,age这里我的数据库名为 root 密码为11.
2.创建一个web project .工程名是myTest1.选择JAVA EE 5.0..点finish.
3导入hibernate.点工程右键,MyEclipse 选择Add hibernate capabilities.上面的不变.下面下面的JAR Library Installation .选择Copy cheched Library..点next .这里不需要修改,点Next.将最上面的勾去掉.我们等下自己写这个factory.点next.再将上面的勾去掉.点finish..
4.导入spring..点工程右键,MyEclipse 选择Add spring capabilities..其中Libraries选择前四个.还有一个Spring 2.0 Web libraries ..一共是五个..下面的JAR Library Installation .选择Copy cheched Library...这个.也就是将加入的jar包复制到lib目录下..点next .在产生applicationContext.xml的目录里选择WebRoot/WEB-INF 点next.把上面的√去掉.等下我们自己写...最后点FINISH.spring就导入成功了
5 导入struts2..现在myeclipse还不支持导入struts2.所以这里我们需要手动导入.方法也很简单..将struts2.0.16客户端的jar包里.选择freemarker.jar,ognl.jar.struts2-spring-plugin.jar.xwork.jar.struts-core.jar.这里不需要导入common-logging.jar.因为spring里面已经有这个jar包了.所以不需要再次导入..然后在src目录下创建一个struts.xml..这样就差不多了.
这里特别注意一下.需要将common-pool.jar包放到Lib目录下..貌似myeclipse6.5就会自动导入.6.0不会的说
6 准备工作差不多了.终于开始写页面了...首先,我们先做一个save.jsp..里面有一个表单,输入名字和年龄..
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'save.jsp' starting page</title>
</head>
<body>
<s:form action="userAction">//注意,我们这里选择模型驱动.而不是字段驱动.
还有,这个action name 设置为 userAction ..
<s:textfield name="user.username" label="username"></s:textfield>
<s:textfield name="user.age" label="age"></s:textfield>
<s:submit></s:submit>
</s:form>
</body>
</html>
7创建bean..这个很简单.就是在com.test.model下面创建一个User.java.标准的bean.没啥可说的
package com.test.model;
public class User {
private Integer id;
private String username;
private int age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
7 开始写action .首先在src下面创建一个com.test.action包.在这个包下面创建UserAction.java
package com.test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.test.model.User;
import com.test.service.UserService;
public class UserAction extends ActionSupport {
private UserService userservice;
private User user;
public UserService getUserservice() {
return userservice;
}
public void setUserservice(UserService userservice) {
this.userservice = userservice;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String execute(){
userservice.saveUser(user);
return SUCCESS;
}
}
这里在流程上已经有点偏了.因为这里我直接写出了userserive.这个类我们还没实现..而在实现这个service以前我们又必须实现userDAO.下一步,我们实现userDAO
8 新建一个包.com.test.DAO 这个是存放DAO接口的..spring要求我们必须面向接口编程 创建一个UserDAO.java
package com.test.DAO;
//这里定义了五个方法.分别是增删改查..查里面有两个,一个是根据ID查,一个是查所有.
import java.util.List;
import com.test.model.User;
public interface UserDAO {
public void addUser(User user);
public void delUser(User user);
public void updateUser(User user);
public User selectById(Integer id);
public List<User> selectAll();
}
9 创建一个com.test.DAO.impl包.实现上面定义的UserDAO ...类名是UserDAOimpl
package com.test.DAO.impl;//这里结合了hibernate.所以我们继承 HibernateDaoSupport来实现相应的操作.都很简单的..就要注意下selectALL方法.里面用到了hql语句
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.test.DAO.UserDAO;
import com.test.model.User;
public class UserDAOimpl extends HibernateDaoSupport implements UserDAO {
@Override
public void addUser(User user) {
this.getHibernateTemplate().save(user);
}
@Override
public void delUser(User user) {
this.getHibernateTemplate().delete(user);
}
@Override
@SuppressWarnings("unchecked")
public List<User> selectAll() {
String hql= "from User";
return (List<User>)this.getHibernateTemplate().find(hql);
}
@Override
public User selectById(Integer id) {
return (User)this.getHibernateTemplate().get(User.class, id);
}
@Override
public void updateUser(User user) {
this.getHibernateTemplate().update(user);
}
}
10创建好了DAO实现数据库的操作..现在开始写Service业务层...由于我们没有任何事务,所以Service就是调用一次DAO层...首先还是创建一个包来放接口.com.test.service ..里面的类UserService.java
package com.test.service;
import java.util.List;
import com.test.model.User;
public interface UserService {//这里也对应DAO.写了五个方法..
public void saveUser(User user);
public void delUser(User user);
public void updateUser(User user);
public User findById(int id);
public List<User> findAll();
}
11同理,当然是写这个service的实现类..com.test.service.impl包..UserServiceImpl.java
package com.test.service.impl;//这里没写什么业务,只是调用了一次dao.
import java.util.List;
import com.test.DAO.UserDAO;
import com.test.model.User;
import com.test.service.UserService;
public class UserServiceImpl implements UserService {
private UserDAO userdao;
public UserDAO getUserdao() {
return userdao;
}
public void setUserdao(UserDAO userdao) {
this.userdao = userdao;
}
@Override
public void delUser(User user) {
userdao.delUser(user);
}
@Override
public List<User> findAll() {
return userdao.selectAll();
}
@Override
public User findById(int id) {
return userdao.selectById(id);
}
@Override
public void saveUser(User user) {
userdao.addUser(user);
}
@Override
public void updateUser(User user) {
userdao.updateUser(user);
}
}
12 最重要的地方开始了.就是配置applicationContext.xml.直接放上来代码,一点点解释吧.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">//配置dataSource.这个部分在hibernate里面说的比较多了.不多说了
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost/user</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>11</value>
</property>
</bean>
<bean id="factory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="mappingResources">
<value>com/test/model/User.hbm.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="UserDao" class="com.test.DAO.impl.UserDAOimpl">
<property name="sessionFactory">//这个部分也说明了.其实就是在DAO里面注入一个factory.我们在调用this.getHibernateTemplate() 的时候必须有这个factory.
<ref bean="factory"/>
</property>
</bean>
<bean id="UserService" class="com.test.service.impl.UserServiceImpl">
<property name="userdao">//在类UserServiceImpl里面定义了一个userdao.这里的这个name属性必须和那里的名字相同.因为要调用那里的set方法.
<ref bean="UserDao"/>//依赖注入.spring里面说了很多了...
</property>
</bean>
<bean >
<property name="userservice">//这个同上了..UserAction里面也有一个相应的set方法..
<ref bean="UserService"/>
</property>
</bean>
<bean id="listActionClass" class="com.test.action.ListAction">
<property name="service">//这个是配置下面list页面的时候用的...先放上来了...免得重复黏贴
<ref bean="UserService"/>
</property>
</bean>
</beans>
13 save页面的最后一步当然是配置struts.xml.结果页面下面再说
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="user" extends="struts-default">
<action name="userAction" class="userActionClass">
<result type="redirect">ListAction.action</result>//这里重定向到ListAction.显示list页面
<result name="input">/save.jsp</result>
</action>
<action name="ListAction" class="listActionClass">
<result >/list.jsp</result>//list页面的action配置
<result name="input">/index.jsp</result>
</action>
</package>
</struts>
14 至此,save页面已经全部完成.但是提交以后总要显示列表信息吧..也就是将数据库里的数据全部取出来显示.所以,我们在com.test.action下面再写一个action.叫ListAction.java
package com.test.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.test.service.UserService;
public class ListAction extends ActionSupport {
private UserService service;
public UserService getService() {
return service;
}
public void setService(UserService service) {
this.service = service;
}
@SuppressWarnings("unchecked")
@Override
public String execute() throws Exception {
Map request = (Map)ActionContext.getContext().get("request");获取一个request的MAP对象
request.put("list", service.findAll());//放入MAP
return SUCCESS;
}
}
15 这里,还忘记一个重要的东西..就是bean对应的hbm.xml 因为我使用Middlegen自动生成的,所以代码多一些..ID的生产策略是加一..
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
<hibernate-mapping>
<!--
Created by the Middlegen Hibernate plugin 2.1
http://boss.bekk.no/boss/middlegen/
http://www.hibernate.org/
-->
<class
name="com.test.model.User"
table="user"
>
<meta attribute="class-description" inherit="false">
@hibernate.class
table="user"
</meta>
<id
name="id"
type="java.lang.Integer"
column="id"
>
<meta attribute="field-description">
@hibernate.id
generator-class="assigned"
type="java.lang.Integer"
column="id"
</meta>
<generator class="increment" />
</id>
<property
name="username"
type="java.lang.String"
column="username"
not-null="true"
length="50"
>
<meta attribute="field-description">
@hibernate.property
column="username"
length="50"
not-null="true"
</meta>
</property>
<property
name="age"
type="int"
column="age"
not-null="true"
length="10"
>
<meta attribute="field-description">
@hibernate.property
column="age"
length="10"
not-null="true"
</meta>
</property>
<!-- Associations -->
</class>
</hibernate-mapping>
16 我忘记了一个非常重要的配置..web.xml.这么重要的东西.不多说了.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
17又忘记一个jar包.就是jdbc连mysql的驱动包..我用的是mysql-connector-java-5.1.7-bin.jar
18 最后是我们的列表页面.list.jsp .里面用到ognl表达式.有空得去学习下
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'list.jsp' starting page</title>
</head>
<body>
<h1><font color="red"><center>User List</center></font></h1>
<table align="center" border="1" width="80%">
<tr>
<td>序号
</td>
<td>名字
</td>
<td>年龄
</td>
<td>删除
</td>
<td>修改
</td>
</tr>
<s:iterator value="#request.list" id="us">
<tr>
<td><s:property value="#us.id"/>
</td>
<td><s:property value="#us.username"/>
</td>
<td><s:property value="#us.age"/>
</td>
<td><s:a href="deleteUser.action?user.id=%{#us.id}">删除</s:a>
</td>
<td><s:a href="updatePUser.action?user.id=%{#us.id}">修改</s:a>
</td>
</tr>
</s:iterator>
</table>
</body>
</html>
19 最后..终于测试通过.