完整JavaWeb项目笔记 第二部分-项目结构及Bean和Dao设计

一 服务端项目结构

  Java开发工具我用的是Eclipse,配置完Maven后,创建的war工程,接下来就是项目目录结构的划分,这一点的重要性说来可大可小,结构清晰,则开发更加顺利,结构不合理则变动会比较频繁,对于体量较小的项目而言虽然影响不大,但是出于习惯的考虑,还是对结构进行下划分:

在这里插入图片描述

  1. bean包中为数据表对应的Java类;
  2. common中放置项目中其他类引用的公用设计;
  3. dao包中放置两部分,一个是数据访问接口设计,一个是接口实现;
  4. filter包中放置Servlet请求过滤器;
  5. service包为服务层设计,所有的业务逻辑实现都在这里;
  6. servlet包下为所有处理请求的Servlet实现类;
  7. util包下则为各类公用函数的实现。

二 表结构设计

  数据表设计不细说了,简简单单几张表,大致看一下对应的Bean就差不多,这里不涉及任何技术问题。但是需要注意的是,表及表字段的命名必须遵守规范,合理的命名规范对于未来可能出现的重构、其他需求而言及其重要,附上Navicat的截图:

项目表结构

三 Bean设计

  这里再提一嘴,所有的bean需要有较为严格的结构设计:

  1. 除和表字段对应的成员属性(私有访问权限),必须有一一对应的属性访问器(getter、setter方法);
  2. 如果有特殊的对象创建需求,则除特殊的构造函数外,必须保留默认的无参数构造;
  3. 必须要重写equals、hashCode方法,方法重写一般使用表主键字段作为主要判断逻辑,重写是为了满足业务逻辑上的等值判断;
  4. 尽量重写toString方法,以便设计时进行日志打印、打桩调试的信息输出。
  5. 需要注意的是bean属性未必需要和表字段结构一一对应,比如说自增字段,虽然常被设置为主键,但是为了方便未来的拆表及数据迁移,我们还是会使用UUID作为其唯一索引,这种情况下自增id字段就没有必要做为bean的属性存在,其查询逻辑中也不应该使用。

  附上大致的设计:

Bean设计

  1. Module为帖子的分类,学习、工作、两性什么的;
  2. Topic为帖子的结构,包括帖子的标题、内容;
  3. TopicReply为帖子的回复内容,包括回复人id、回复时间等;
  4. TopicInof则为帖子的附加信息,回复数量、发表时间、作者等信息;
  5. User为用户信息,包括用户的账号、密码等;
  6. UserSession为用户会话信息,包括登陆时间、token有效期等。

  以Module为例:

package com.bubbling.bean;

import java.util.Date;

public class Module
{
	private String name;
	private String description;
	private Date creatime;
	private Date updatime;

	public Module()
	{
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public String getDescription()
	{
		return description;
	}

	public void setDescription(String description)
	{
		this.description = description;
	}

	public Date getCreatime()
	{
		return creatime;
	}

	public void setCreatime(Date creatime)
	{
		this.creatime = creatime;
	}

	public Date getUpdatime()
	{
		return updatime;
	}

	public void setUpdatime(Date updatime)
	{
		this.updatime = updatime;
	}

	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Module other = (Module) obj;
		if (name == null)
		{
			if (other.name != null)
				return false;
		}
		else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString()
	{
		return "Module [name=" + name + ", description=" + description + ", creatime=" + creatime + ", updatime="
				+ updatime + "]";
	}

}

三 Dao设计

  Dao层为数据访问接口,我们所有的设计要尽量面向接口,虽然当下我们的实现采用的是Mysql数据库,且实现为JDBC的方式,但是难保以后不会有实现上的改变,如果有,那么接口的意义就大了,对应用设计来说,整体结构无需任何变化,仅接口实现改变即可。

  对Dao的设计,需要充分考虑应用对表数据的访问需求,不能一味的按增删改查需求设计,而对于MVC分层结构的设计来说,对请求的业务处理应该交由服务层实现,也就是说Service应该是Dao的使用大户,那么Dao的接口设计就应该主要考虑Service的实现需求。

  Dao也不多说,对于这个项目而言,主要就三个数据访问需求:

  1. Module,模块
  2. Topic,帖子
  3. User,用户

  贴一张参考图:

Dao设计

  以ModuleDao为例,介绍下接口定义及其实现:

package com.bubbling.dao;

import java.util.List;

import com.bubbling.bean.Module;

public interface ModuleDao
{
	public boolean addModule(String name, String description);

	public Module getModuleByUuid(String uuid);

	public List<Module> getModuleList();
}

  ModuleDaoMysqlImpl实现:

package com.bubbling.dao.impl.mysql;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.bubbling.bean.Module;
import com.bubbling.dao.ModuleDao;
import com.bubbling.util.DatabaseUtil;

public class ModuleDaoMysqlImpl implements ModuleDao
{

	private static final String SqlAddModule = "INSERT INTO module ( `uuid`, `name`, `description`, `creatime` ) VALUES ( REPLACE (UUID(), '-', ''), ?, ?, NOW())";

	@Override
	public boolean addModule(String name, String description)
	{
		Connection conn = null;
		PreparedStatement st = null;
		boolean ret = false;
		int index = 1;
		try
		{
			conn = DatabaseUtil.getConnection();
			st = conn.prepareStatement(SqlAddModule);
			st.setString(index++, name);
			st.setString(index++, description);
			int i = st.executeUpdate();
			if (i > 0)
			{
				ret = true;
			}
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
		finally
		{
			DatabaseUtil.close(conn, st);
		}
		return ret;
	}

	private static final String SqlGetModuleByUuid = "SELECT `name`, `description` FROM module WHERE uuid = ?";

	@Override
	public Module getModuleByUuid(String uuid)
	{
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		Module module = null;
		int index = 1;
		try
		{
			conn = DatabaseUtil.getConnection();
			st = conn.prepareStatement(SqlGetModuleByUuid);
			st.setString(index++, uuid);
			rs = st.executeQuery();
			if (rs.next())
			{
				module = new Module();
				module.setName(rs.getString("name"));
				module.setDescription(rs.getString("description"));
			}
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
		finally
		{
			DatabaseUtil.close(conn, st, rs);
		}
		return module;
	}

	private static final String SqlGetModuleList = "SELECT `name`, `description` FROM module";

	@Override
	public List<Module> getModuleList()
	{
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		List<Module> ret = new ArrayList<>();
		try
		{
			conn = DatabaseUtil.getConnection();
			st = conn.prepareStatement(SqlGetModuleList);
			rs = st.executeQuery();
			while (rs.next())
			{
				Module module = new Module();
				module.setName(rs.getString("name"));
				module.setDescription(rs.getString("description"));
				ret.add(module);
			}
			if (ret.size() == 0)
			{
				ret = null;
			}
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
		finally
		{
			DatabaseUtil.close(conn, st, rs);
		}
		return ret;
	}
}

  注意,上例中数据库连接的获取及关闭定义在了DatabaseUtil中,数据库方面设计将在后面的部分介绍,数据库连接池采用阿里的Druid,数据源配置采用JNDI。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬睡客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值