★★JSP+Struts+Mysql构建的MVC三层框架对一张数据表的CURD

时间:2022-07-19 14:48:03

项目实现流程

1.        建立工程(struts2CURD),拷贝jar包,建立struts.xml文件,搭建环境

2.        建立数据库和数据源配置:dbcpconfig.properties

3.        建立db.sql:里面全是数据库操作的一些语句

4.        建立操作数据库的工具:*.util:DBCPUtil.java,用于加载数据源。getDataSource();

5.        *.Domain:User.java继承ActionSupport,实现Serializable接口。

       写好字段;生成get和set方法;建立toString方法(方便调试)

6.        建立Dao层(先接口后实现):*.Dao:UserDao.java(这个要按需求来做,优先考虑返回值)

实现功能

界面

方法原型

查询所有用户

显示

public List<User> findAllUsers(){}

根据查询条件查询客户

查询

public List<User> findUsersByCondition(String condition){}

添加用户到数据库

添加

public void addUser(User user){}

根据Id组件获取用户信息

查看

public User findUserById(String userId){}

修改客户信息

编辑

public void updateUser(User user){}

根据用户的ID删除记录

删除

public void deleteUser(String userId){}

7.        实现Dao接口:*.dao.impl:UserDaoMysqlImpl.java

8.        建立“异常库”:*.Exception:DaoException.java

9.        写加密工具类:*.util:MD5Util.java

10.    *.test:单元测试

开发后台

1.      显示信息界面:listUsers.jsp和默认主页index.jsp

2.      建立UserService.java接口

3.      建立UserServiceImpl.java实现UserService类

4.      在User.java中补充相应方法

5.      在listUsers.jsp页面中添加“添加”用户的按钮链接。在User.java中添加addUser()方法。建立addUser.jsp页面,实现添加功能。

注意:在最初开始写addUser()方法时应该通过System.out.println(this);来检验是否在控制台可以得到前台输入的数据。

添加验证规则

6.      在domain下建立验证规则(用户输入数据的规则)的xml文档:User-user_addUser-validation.xml。

7.      实现综合模糊查询功能:在listUsers.jsp中添加相应项。在User.java中添加queryCondition()方法。

8.      实现删除功能……

9.      实现编辑功能……

10.  ★★★Date转换功能,系统体现的功能不适合。建立xwork-conversion.properties文件(java.util.Date=cn.hw.convertor.

DateConvertor)

建立DateConvertor.java类,继承:DefaulttypeConvert类,覆盖convertValue()方法

11.  实现查看功能…… showUser.jsp

12.  实现下载功能……

13.  用拦截器实现的必须登陆才能进行操作。

*.interceptor:PermissionInterceptor.java实现Interceptor接口(注意是opensymphony的不是sun的)

在顺

14.  写login.jsp

总结

继承com.opensymphony.xwork2.ActionSupport

我们自己写的动作类继承com.opensymphony.xwork2.ActionSupport的理由

先了解Action接口有:

     public static final java.lang.StringSUCCESS = "success";

public static final java.lang.String NONE = "none";

     public static final java.lang.String ERROR= "error";

     public static final java.lang.String INPUT= "input";

     public static final java.lang.String LOGIN= "login";

     public abstract java.lang.String execute()throws java.lang.Exception;

(1)   ActionSupport实现了Action类,这样利用该类中定义的这些常量来完成页面与动作类之间的交互。

(2)   ActionSupport实现了很多的实用接口,大大的简化我们自己书写动作类的开发。

(a)   开发中常利用该类中的validate()方法:会自动执行在execute()之前,如校验失败,会转入input处,必须在配置该Action时配置input属性

(b)   重载该类中的execute()方法:

(c)   ActionSupport还提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息,这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化

为什么要实现Serializable接口?

一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。一般以下三种情况都需要实现Serializable接口

(a)   当你想把的内存中的对象写入到硬盘的时候。比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把它拿出来用,那么这时候就要实现Serializable接口;

(b)   当你想用套接字在网络上传送对象的时候。在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。

(c)   当你想通过RMI传输对象的时候。如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。

serialVersionUID的作用 ?

serialVersionUID:字面意思上是序列化的版本号。warning的功能,在你实现序列化的类上会有这个警告,点击会出现增加这个版本号。这个版本号就是确保了不同版本之间的兼容性,不仅能够向前兼容,还能够向后兼容,即在版本升级时反序列化仍保持对象的唯一性。它有两种生成方式:一个是默认的1L,比如:private static final longserialVersionUID = 1L;一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:privatestatic final long serialVersionUID = xxxxL;

在写代码时应该从后台开始往前台,还是从前台往后台开始写?

如果对业务不是很熟,则应该从页面的需求开始逐步从action层向service层写。Dao层可以分开,提供一些常用的数据库操作方法,当写到service层,如果dao层提供的方法不能满足条件,然后再在dao层补充相关的方法以供service层使用。但切记不要写完dao层直接写service层,除非对业务非常的熟悉。所以一般情况下,采取从两头向中间写代码比较稳妥。

★★页面转向的方式有下面几种

(1)   当转向的是一个纯粹的页面时,即没有动作请求,不要从后台请求数据,则通过<a href=""/>可以直接转到相应的前台页面,前台页面之间的跳转。如主页面上点击添加用户按钮,页面转向用户添加数据的页面。

(2)   当页面向后台请求一个动作并且传输数据(如:查询或删除)时。要将相关数据提交给后台,然后后台依据该数据形成的条件今进行后台操作,最后返回相应数据至前台页面显示。这种要将数据提交给后台的动作请求,需要用表单进行操作,一般有下面三种方式可以选择。

<form action="${pageContext.request.conextPath}/queryUser?operation=…"method="post">
... <input type="submit" value="添加"/>
</form>
<s:form action="user_queryCondition"namespace="/user">
... <s:submit value="查询"></s:submit>
</s:form><!--查询结果数据在本页面显示-->
<s:url action="user_delUser"namespace="/user"var="url">
<s:param name="userId" value="#user.id"></s:param>
</s:url>
<a href="<s:property value='url'/>">删除</a><!--删除、编辑、修改都可用这种方式-->

难点:上传和下载

上传(结合struts2框架)+ 数组形式字段的处理

【UserAction.java】相关字段见下面(2)-(a)

【addUser.jsp】

<s:form action="user_addUser"namespace="/user"enctype="multipart/form-data">
<s:filename="image"label="照片"></s:file>
</s:form>

 【UserAction:addUser()】

public String addUser(){
//System.out.println(this);//★打印到控制台上,验证jsp页面的数据能不能获得
//1.★★单独处理hobby
if(hobbies!=null&&hobbies.length>0){
StringBuffersb = new StringBuffer();
for(int i=0;i<hobbies.length;i++){
if(i>0)
sb.append(",");
sb.append(hobbies[i]);
}
hobby = sb.toString();
}
//单独处理:filename、storePath、path
/*2.1★★单独处理filename,上传到文件存储时必须以不同的文件名存储,防止多名用户上传相同文件名文件*/
filename= UUID.randomUUID().toString()+"_"+imageFileName;
//2.2得到存放文件根目录files的真实路径
StringstorePath = ServletActionContext.getServletContext().getRealPath("/files");
//2.3计算存放的子路径:自动随机生成两级目录
path = WebUtil.makeDirs(storePath,filename);
//3.★★文件上传
try {
//common.io包中的:FileUtils.copyFile():拷贝文件到新的文件中并且保存最近修改时间
FileUtils.copyFile(image,new File(storePath+"\\"+path+"\\"+filename));
} catch (IOException e){
e.printStackTrace();
}
s.addUser(this); //4.★将user放进去
ActionContext.getContext().put("message","保存成功!");
return "saveOK";
}

【WebUtil.java】

public class WebUtil{
public static String makeDirs(StringstorePath, String filename){
int hashCode = filename.hashCode();
int dir1 = hashCode&0xf;//最低四位
int dir2 =(hashCode&0xf0)>>4;//其余四位
String newPath = dir1+"\\"+dir2;
File file = new File(storePath,newPath);
if(!file.exists())
file.mkdirs();
return newPath;
}
}

下载(结合struts2框架)

下面的方法中利用EL表达式和struts中OGNL表达式进行传值+简单权限拦截

下面与下载相关的参数说明:

contentType :内容类型,和互联网MIME标准中的规定类型一致,例如text/plain代表纯文本text/xml表示XML,image/gif代表GIF图片,image/jpeg代表JPG图片

inputName:下载文件的来源流,对应着action类中某个类型为Inputstream的属性名,例如取值为inputStream的属性需要编写getInputStream()方法

contentDisposition :文件下载的处理方式,包括内联(inline)和附件(attachment)两种方式,而附件方式会弹出文件保存对话框否则浏览器会尝试直接显示文件。取值为:attachment;filename="struts2.txt",表示文件下载的时候保存的名字应为struts2.txt。如果直接写filename="struts2.txt",那么默认情况是代表inline,浏览器会尝试自动打开它,等价于这样的写法:inline; filename="struts2.txt"

bufferSize:下载缓冲区的大小

(a)   【UserAction.java】

public class User extendsActionSupportimplements Serializable{
//...其它字段和相应的setter和getter方法
private String path;//文件保存的路径
private String filename;//存的文件名 UUID_老文件名
//文件上传的相关字段
private File image;
private String imageFileName;
private String imageContentType;
private InputStream inputStream;//★文件下载的相关字段:文件下载需要的流
private UserService s = new UserServiceImpl();
public String download(){
path = ServletActionContext.getRequest().getParameter("path");
filename = ServletActionContext.getRequest().getParameter("filename");
StringstorePath = ServletActionContext.getServletContext().getRealPath("/files");
try {
inputStream = new FileInputStream(storePath+"\\"+path+"\\"+filename);//★组织路径:构建传输流
} catch (FileNotFoundException e){
e.printStackTrace();
}
return SUCCESS;
}
}

(b)   【download.jsp】

<pre name="code" class="html"><c:url value="/user/download"var="url">
<c:param name="path" value="${user.path}"></c:param>
<c:param name="filename" value="${user.filename}"></c:param>
</c:url>
<a href="${url}">下载</a>


(c)   【struts.xml】

<package name="user" namespace="/user" extends="struts-default">
<actionname="download"class="cn.hw.domain.User"method="download">
<interceptor-refname="mydefaultstack"></interceptor-ref>
<!-- 拦截器,登录以后才可以进行下载-->
<result type="stream" name="success">
<paramname="contentType">application/octet-stream</param>
<!-- octet-stream表示二进制流? -->
<paramname="inputStream">inputStream</param>
<!-- ★输入是对应的动作类中的那个字段,指定输入流是哪个 -->
<paramname="contentDisposition">attachment;filename=${filename}</param>
<!-- 要下载的文件名,主要加头attachment,否则会吐到浏览器上面-->
</result>
<result name="login">/login.jsp</result>
</action>
</package>

(d)   【PermissionInterceptor.java】定义拦截器,并在struts.xml中进行配置

public class PermissionInterceptor implements Interceptor{
public String intercept(ActionInvocationinvocation)throws Exception{
HttpSession session = ServletActionContext.getRequest().getSession();
Object obj = session.getAttribute("user");
if(obj==null){
return"login";
}else{
return invocation.invoke();
}
}
///其它方法省略
}

(e)登录的相关代码和页面等省略