-
项目实现流程
大体流程:搭建环境
à
开发后台
à
开发前台- 建立工程(struts2CURD),拷贝jar包,建立struts.xml文件,搭建环境
- 建立数据库和数据源配置:dbcpconfig.properties
- 建立db.sql:里面全是数据库操作的一些语句
- 建立操作数据库的工具:*.util:DBCPUtil.java,用于加载数据源。getDataSource();
- *.Domain:User.java 继承ActionSupport,实现Serializable接口。
????写好字段;生成get和set方法;建立toString方法(方便调试)
- 建立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)
{}- 实现Dao接口:*.dao.impl:UserDaoMysqlImpl.java
- 建立"异常库":*.Exception:DaoException.java
- 写加密工具类:*.util:MD5Util.java
- *.test:单元测试
开发后台
- 显示信息界面:listUsers.jsp和默认主页index.jsp
- 建立UserService.java接口
- 建立UserServiceImpl.java实现UserService类
- 在User.java中补充相应方法
- 在listUsers.jsp页面中添加"添加"用户的按钮链接。在User.java中添加addUser()方法。建立addUser.jsp页面,实现添加功能。
注意:在最初开始写addUser()方法时应该通过System.out.println(this);来检验是否在控制台可以得到前台输入的数据。
添加验证规则
- 在domain下建立验证规则(用户输入数据的规则)的xml文档:User-user_addUser-validation.xml。
- 实现综合模糊查询功能:在listUsers.jsp中添加相应项。在User.java中添加queryCondition()方法。
- 实现删除功能……
- 实现编辑功能……
- ★★★Date转换功能,系统体现的功能不适合。建立xwork-conversion.properties文件(java.util.Date=cn.hw.convertor.
DateConvertor)
建立DateConvertor.java类,继承:DefaulttypeConvert类,覆盖convertValue()方法
- 实现查看功能…… showUser.jsp
- 实现下载功能……
- 用拦截器实现的必须登陆才能进行操作。
*.interceptor:PermissionInterceptor.java 实现Interceptor接口(注意是opensymphony的不是sun的)
在顺
- 写login.jsp
-
总结
- 我们自己写的动作类继承com.opensymphony.xwork2.ActionSupport的理由:
先了解Action接口有:
????public static final java.lang.String SUCCESS = "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;
- ActionSupport实现了Action类,这样利用该类中定义的这些常量来完成页面与动作类之间的交互。
- ActionSupport实现了很多的实用接口,大大的简化我们自己书写动作类的开发。
- 开发中常利用该类中的validate()方法:会自动执行在execute()之前,如校验失败,会转入input处,必须在配置该Action时配置input属性
- 重载该类中的execute()方法:
- ActionSupport还提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息,这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化
- 为什么要实现Serializable接口?
一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。一般以下三种情况都需要实现Serializable接口
- 当你想把的内存中的对象写入到硬盘的时候。比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把它拿出来用,那么这时候就要实现Serializable接口;
- 当你想用套接字在网络上传送对象的时候。在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。
- 当你想通过RMI传输对象的时候。如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。
- serialVersionUID的作用 ?
serialVersionUID:字面意思上是序列化的版本号。warning的功能,在你实现序列化的类上会有这个警告,点击会出现增加这个版本号。这个版本号就是确保了不同版本之间的兼容性,不仅能够向前兼容,还能够向后兼容,即在版本升级时反序列化仍保持对象的唯一性。
它有两种生成方式:一个是默认的1L,比如:private static final long serialVersionUID = 1L;一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:private static final long serialVersionUID = xxxxL;
4. 在写代码时应该从后台开始往前台,还是从前台往后台开始写?
如果对业务不是很熟,则应该从页面的需求开始逐步从action层向service层写。Dao层可以分开,提供一些常用的数据库操作方法,当写到service层,如果dao层提供的方法不能满足条件,然后再在dao层补充相关的方法以供service层使用。但切记不要写完dao层直接写service层,除非对业务非常的熟悉。所以一般情况下,采取从两头向中间写代码比较稳妥。
- ★★页面转向的方式有下面几种
- 当转向的是一个纯粹的页面时,即没有动作请求,不要从后台请求数据,则通过<a href=""/>可以直接转到相应的前台页面,前台页面之间的跳转。如主页面上点击添加用户按钮,页面转向用户添加数据的页面。
- 当页面向后台请求一个动作并且传输数据(如:查询或删除)时。要将相关数据提交给后台,然后后台依据该数据形成的条件今进行后台操作,最后返回相应数据至前台页面显示。这种要将数据提交给后台的动作请求,需要用表单进行操作,一般有下面三种方式可以选择。
<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><!--删除、编辑、修改都可用这种方式-->
- 利用JSP+Struts2+Mysql技术构建MVC三层框架实现一张数据表的CURD难点
- 上传(结合struts2框架)+ 数组形式字段的处理
【UserAction.java】相关字段见下面(2)-(a)
【addUser.jsp】
<s:form
action="user_addUser"
namespace="/user"
enctype="multipart/form-data">
<s:file
name="image"
label="照片"></s:file>
</s:form>
????????【UserAction:addUser()】
public String addUser(){
//System.out.println(this);//★打印到控制台上,验证jsp页面的数据能不能获得
//1.★★单独处理hobby
if(hobbies!=null&&hobbies.length>0){
StringBuffer sb =
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的真实路径
String storePath = 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(String storePath, 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:下载缓冲区的大小
- 【UserAction.java】
public
class User extends ActionSupport implements 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");
String storePath = ServletActionContext.getServletContext().getRealPath("/files");
try
{inputStream =
new FileInputStream(storePath+"\\"+path+"\\"+filename);//★组织路径:构建传输流}
catch
(FileNotFoundException e)
{e.printStackTrace();
}
return SUCCESS;
}
}
- 【download.jsp】
<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>- 【struts.xml】
<package
name="user"
namespace="/user"
extends="struts-default">
<action
name="download"
class="cn.hw.domain.User"
method="download">
<interceptor-ref
name="mydefaultstack"></interceptor-ref>
<!-- 拦截器,登录以后才可以进行下载-->
<result
type="stream"
name="success">
<param
name="contentType">application/octet-stream</param>
<!-- octet-stream表示二进制流? -->
<param
name="inputStream">inputStream</param>
<!-- ★
输入是对应的动作类中的那个字段,指定输入流是哪个 -->
<param
name="contentDisposition">attachment;filename=${filename}</param>
<!-- 要下载的文件名,主要加头attachment,否则会吐到浏览器上面 -->
</result>
<result
name="login">/login.jsp</result>
</action>
</package>
- 【PermissionInterceptor.java】定义拦截器,并在struts.xml中进行配置
public
class PermissionInterceptor implements Interceptor {public String intercept(ActionInvocation invocation)
throws Exception {HttpSession session = ServletActionContext.getRequest().getSession();
Object obj = session.getAttribute("user");
if(obj==null){
return
"login";}else{
return invocation.invoke();
}
}
///其它方法省略
}
- 登录的相关代码和页面等省略