java web中分层MVC的意义

本文详细介绍了Web编程中的分层架构,包括实体层、基础层、DAO层、业务逻辑层、行动层、数据传输层和工具层等内容。通过具体示例阐述了各层的功能及相互之间的调用关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在web编程中,由于高内聚、低耦合的特点,需要将多个类实现多层,大致有以下几层:
①entity,实体类,如user,role等,这些类里边包含了私有属性和公共的get、set方法这和数据库中的表相对应,更严格一些,包括字段的顺序和type都要保持一致。
②base,封装了基本的操作数据库的方法(增删改查)
③dao,访问并操作数据库,若想从数据库获取数据,必须调用dao层。dao层没有一点业务逻辑,全是跟数据库操作有关的类
④service,业务逻辑层,里边可以是接口。只要没有访问数据库的操作,都写到service层中。

举个例子说明什么是业务。如做一个分页功能,数据1000条,每页20条,则可以把这个功能写成工具类封装起来,然后在业务层调用这个封装的方法,这才是业务层要做的事。

service层和dao层有什么区别?
再举个例子,如注册用户时,还想往日志表里添加一个日志,那么就要在业务层来实现这个操作,并对该操作添加事务,效果会更好。若不使用service,只用dao的话,那么就要连续使用userDao和logDao,那么万一某一步出错,就可能造成user加进去而log没有添加成功。

⑤action,也就是原来的servlet,位于jsp和service层之间进行交互。主要的操作就是请求(request)和响应(response)。存取某个功能的整体实现方法。

以后不要在servlet中调用dao层,而要写到serviceImpl(对接口的实现层)中,如以前的userServlet中有
private UserDao udao = new UserDaoImpl();//private必须写
以后这一句要写到UserServiceImpl内。

⑥vo,数据传输层,用来转入转出数据,跟前台有关。
⑦util,工具类,用来封装一些公用的方法,如字符串的处理,字符集过滤等。

⑧impl,用来实现接口。一个接口可以有多种实现,用来满足不同需要。

一般的调用情况如下:


贴一张很重要的图,大致说明了各层的继承和implements关系




举一个小项目的例子,实现往数据库增删改查用户。缩略图如下:


其中User.java和UserVO.java现在看起来内容相同,区别在于User类是底层数据,一般不轻易改变。UserVO层业余数据库中内容相对应,将DB中检索出数据,或者要往DB中反映的数据保存在vo实例中。以后若想再有什么扩展,直接在VO层改就行,不用动底层代码。

这里边,UserDao,BaseDao,UserService都是接口类,相应的impl则是对其的实现

1.BaseDao代码:

import java.util.List;
/**
 * 基本的方法
 * @author Administrator
 *
 */
public interface BaseDao<Entity> {

	/**
	 * 保存
	 * @param obj
	 * @throws Exception
	 */
	void save(Entity entity) throws Exception;
	/**
	 * 删除
	 * @param id
	 * @throws Exception
	 */
	void delete(int id) throws Exception;
	/**
	 * 更新
	 * @param obj
	 * @throws Exception
	 */
	void update(Entity entity) throws Exception ;
	/**
	 * 根据id查询指定记录
	 * @param id
	 * @return
	 * @throws Exception
	 */
	Entity findById(int id) throws Exception;
	/**
	 * 查询所有记录
	 * @return
	 * @throws Exception
	 */
	List<Entity> findAll() throws Exception;
	
	
}

2.BaseDaoImpl代码,利用反射获取数据库数据

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import com.bjsxt.util.DBUtil;

public class BaseDaoImpl<Entity> implements BaseDao<Entity> {
	
	protected Class clazz;
	
	public BaseDaoImpl(){
		ParameterizedType pz = (ParameterizedType) this.getClass().getGenericSuperclass();
		//利用反射返回当前类的父类的类型,并强制转换
		clazz = (Class) pz.getActualTypeArguments()[0];
		//返回此类型实际类型参数的Type对象数组的第一个
		//这两步的作用就是获取父类泛型参数的实际类型
		System.out.println(clazz + "这是测试代码,打印出来的");
	}
	
	
	@Override
	public void save(Entity entity) throws Exception {
		Connection conn = DBUtil.getConn();//连接数据库
		String sql = "insert into " + clazz.getSimpleName() + " values(null";
		Field[] fs = clazz.getDeclaredFields(); 
		for (int i = 0; i < fs.length; i++) {
			sql += ",?";
		}
		sql = sql + ")";
		PreparedStatement ps = DBUtil.getPs(conn, sql);
		//user.setUsername(rs.getString("username"));
		for (int i = 0; i < fs.length; i++) {
			String methodName = "get" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
			//假如有个实体user类,含有uname属性,则获取uname的方法默认会为getUname(),会将uname的首字母大写,其余不变
			//Character.toUpperCase就是将字符大写,然后将除首字母以外的截取出来,拼到一起,构成类似于getUname()的方法
			//user.setUsername(uForm.getUsername);  
			//该处用get是因为要把对象保存进数据库里,用get获取属性
			Method m = clazz.getDeclaredMethod(methodName);
			ps.setObject(i,m.invoke(entity));
			//setObject用来给"?"赋值。invoke则是在不知道具体类的情况下利用字符串去调用方法
			//正常情况下是user.getUsername,m.invoke(entity)中m是一个方法,类似于getUsername(),entity相当于user.
			//invoke是从实体里边找方法,那句话的意思就是从实体里边调用方法
		}
		ps.executeUpdate();
		DBUtil.close(ps);
		DBUtil.close(conn);
	}

	@Override
	public void view(Entity entity) throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void update(Entity entity) throws Exception {
		Connection conn = DBUtil.getConn();
		String sql = "update " + clazz.getSimpleName() + "set";
		Field[] fs = clazz.getDeclaredFields();
		for (int i = 0; i < fs.length; i++) {
			sql += fs[i].getName() + " = ?,";
		}
		sql = sql.substring(0,sql.length()-1) + " where id = ?"; //减去最后的逗号
		PreparedStatement ps = DBUtil.getPs(conn, sql);
		for (int i = 0; i < fs.length; i++) {
			String methodName = "get" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
			Method m = clazz.getDeclaredMethod(methodName);
			ps.setObject(i, m.invoke(entity));
		}
		Method getId = clazz.getDeclaredMethod("getId");//更新需要知道id
		ps.setInt(fs.length, (Integer) getId.invoke(entity));//因为id在sql语句最后一个问号处,所以要用fs.length
		ps.executeUpdate();
		DBUtil.close(ps);
		DBUtil.close(conn);
		
	}

	@Override
	public void delete(int id) throws Exception {
		Connection conn = DBUtil.getConn();
		String sql = "delete from " + clazz.getSimpleName() + " where id = ?" + id;
		PreparedStatement ps = DBUtil.getPs(conn, sql);
		ps.executeUpdate();
		DBUtil.close(ps);
		DBUtil.close(conn);
	}

	@Override
	public Entity findById(int id) throws Exception {
		Connection conn = DBUtil.getConn();
		String sql = "select * from " + clazz.getSimpleName() + " where id= ? ";
		PreparedStatement ps = DBUtil.getPs(conn, sql);
		ps.setInt(1,id);
		ResultSet rs = ps.executeQuery();
		Entity entity = (Entity) clazz.newInstance();//利用无参构造函数新建实例
		Field[] fs = clazz.getDeclaredFields();
		if(rs.next()){
			for (int i = 0; i < fs.length; i++) {
				String methodName = "set" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
				Method m = clazz.getDeclaredMethod(methodName, fs[i].getType());
				m.invoke(entity, rs.getObject(fs[i].getName()));
			}
		}
		DBUtil.close(rs);
		DBUtil.close(ps);
		DBUtil.close(conn);
		
		return entity;
	}

	@Override
	public List<Entity> findAll() throws Exception {
		Connection conn = DBUtil.getConn();
		String sql = "select * from " + clazz.getSimpleName();
		PreparedStatement ps = DBUtil.getPs(conn, sql);
		ResultSet rs = ps.executeQuery();
		List<Entity> enList = new ArrayList<Entity>();
		while(rs.next()){
			Entity en = (Entity) clazz.newInstance();
			//user.setUsername(rs.getString("username"));
			Field[] fs = clazz.getDeclaredFields();
			for (int i = 0; i < fs.length; i++) {
				String methodName = "set" + Character.toUpperCase(fs[i].getName().charAt(0)) + fs[i].getName().substring(1);
				Method m = clazz.getDeclaredMethod(methodName, fs[i].getType());
				m.invoke(en, rs.getObject(fs[i].getName()));
			}
			enList.add(en);
		}
		DBUtil.close(rs);
		DBUtil.close(ps);
		DBUtil.close(conn);
		return enList;
	}
	
}
注意: String methodName在何处用get,何处用set

3.UserDao代码

import java.util.List;

import com.bjsxt.base.BaseDao;
import com.bjsxt.entity.User;

public interface UserDao  extends BaseDao<User>{

	List<User> findByPageList(int currentPage, int pageSize) throws Exception;

	Long getTotal() throws Exception;

}

4.UserDaoImpl代码

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

import sun.nio.cs.US_ASCII;

import com.bjsxt.base.BaseDaoImpl;
import com.bjsxt.dao.UserDao;
import com.bjsxt.entity.User;
import com.bjsxt.util.DBUtils;

public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao{

	@Override
	public List<User> findByPageList(int currentPage, int pageSize)
			throws Exception {
		Connection conn = DBUtils.getConn();
		String sql = "select * from user limit " + (currentPage-1)*pageSize + "," +pageSize;
		PreparedStatement ps = DBUtils.getPs(conn, sql);
		ResultSet rs = ps.executeQuery();
		List<User> userlist =new ArrayList<User>();
		while(rs.next()){
			User user = new User();
			user.setId(rs.getInt("id"));
			user.setUsername(rs.getString("username"));
			user.setPassword(rs.getString("password"));
			user.setAge(rs.getInt("age"));
			user.setSex(rs.getString("sex"));
			user.setBirthday(rs.getString("birthday"));
			user.setSalary(rs.getString("salary"));
			user.setDescription(rs.getString("description"));
			userlist.add(user);
		}
		DBUtils.close(rs);
		DBUtils.close(ps);
		DBUtils.close(conn);
		return userlist;
	}

	@Override
	public Long getTotal() throws Exception {
		Connection conn = DBUtils.getConn();
		String sql = "select count(*) from user";
		PreparedStatement ps = DBUtils.getPs(conn, sql);	
		ResultSet rs =ps.executeQuery();
		if(rs.next()){
			return ((Number)rs.getInt(1)).longValue();
		}
		return ((Number)0).longValue();
	}

}
5.User代码,下边的UserVO先和它一样,就不贴了。

public class User {

	private int id ; 
	private String username ; 
	private String password ; 
	private int age ; 
	private String sex ; 
	private String birthday ; 
	private String salary ; 
	private String description ;
	
	
	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	public User(int id, String username, String password, int age, String sex,
			String birthday, String salary, String description) {
		super();
		this.id = id;
		this.username = username;
		this.password = password;
		this.age = age;
		this.sex = sex;
		this.birthday = birthday;
		this.salary = salary;
		this.description = description;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	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 int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getBirthday() {
		return birthday;
	}
	public void setBirthday(String birthday) {
		this.birthday = birthday;
	}
	public String getSalary() {
		return salary;
	}
	public void setSalary(String salary) {
		this.salary = salary;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	} 
	
}
6.UserService代码,只提供接口,不实现任何方法,只让UserServiceImpl来实现

import java.util.List;

import com.bjsxt.util.DataGrid;
import com.bjsxt.vo.UserVO;

public interface UserService {
	
	void saveUser(UserVO userVO) throws Exception ; 
	
	void deleteUser(int id) throws Exception ;
	
	void updateUser(UserVO userVO) throws Exception ;
	
	UserVO findById(int id) throws Exception ; 
	
	List<UserVO> findAll() throws Exception ;
	
	DataGrid findByPage(int currentPage , int PageSize) throws Exception ;
	
	
}

7.UserServiceImpl代码,方法还没完全实现,只完成一种。

import java.nio.channels.DatagramChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.bjsxt.dao.UserDao;
import com.bjsxt.dao.impl.UserDaoImpl;
import com.bjsxt.entity.User;
import com.bjsxt.service.UserService;
import com.bjsxt.util.DataGrid;
import com.bjsxt.vo.UserVO;

public class UserServiceImpl implements UserService {
	
	
	private UserDao userDao  = new UserDaoImpl();

	@Override
	public void saveUser(UserVO userVO) throws Exception {
		
	}

	@Override
	public void deleteUser(int id) throws Exception {
		
	}

	@Override
	public void updateUser(UserVO userVO) throws Exception {
		
	}

	@Override
	public UserVO findById(int id) throws Exception {
		return null;
	}

	@Override
	public List<UserVO> findAll() throws Exception {
		return null;
	}

	@Override
	public DataGrid findByPage(int currentPage, int PageSize)
			throws Exception {
		List<UserVO> uservolist = new ArrayList<UserVO>();
		List<User> userList = this.userDao.findByPageList(currentPage ,PageSize);
		for (Iterator iterator = userList.iterator(); iterator.hasNext();) {
			User user = (User) iterator.next();
			UserVO uvo = new UserVO();
			uvo.setId(user.getId());
			uvo.setUsername(user.getUsername());
			uvo.setPassword(user.getPassword());
			uvo.setAge(user.getAge());
			uvo.setBirthday(user.getBirthday());
			uvo.setSalary(user.getSalary());
			uvo.setSex(user.getSex());
			uvo.setDescription(user.getDescription());
			uservolist.add(uvo);
		}
		
		Long total = this.userDao.getTotal();
		DataGrid datagrid = new DataGrid();
		datagrid.setRows(uservolist);
		datagrid.setTotal(total);
		
		return datagrid;
	}

}
8.DataGrid代码

import java.util.List;

public class DataGrid {

	private Long total ; 	//总记录数
	private List rows  ;	//返回的数据条目
	public Long getTotal() {
		return total;
	}
	public void setTotal(Long total) {
		this.total = total;
	}
	public List getRows() {
		return rows;
	}
	public void setRows(List rows) {
		this.rows = rows;
	}
	
	
}

9.DBUtil代码

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 链接数据库的
 * @author Administrator
 *
 */
public class DBUtils {

	/**
	 * 获得connection对象
	 * @return
	 */
	public static  Connection getConn(){
		Connection conn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost/ext_001", "root", "root");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}
	
	/**
	 * 预编译sql
	 * @param conn
	 * @param sql
	 * @return
	 */
	public static PreparedStatement getPs(Connection conn , String sql){
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(sql);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return ps;
	}
	
	/**
	 * 一系列关闭对象的close
	 * @param conn
	 */
	
	
	public static void close(Connection conn){
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static  void close(PreparedStatement ps){
		if(ps != null){
			try {
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}		
	}
	
	public static  void close(ResultSet rs){
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}		
	}
}

最后粘一篇百度知道上的内容,关于service层和dao层的,供参考。

首先,service层会很大,方法很多。
第二,试想,所有DAO都有增删改查四个基本方法。假设在DAO层(如StudentDAO.java)里student.add(),student.delete().student.update(),student.query()。
而如果应用增加了service层(如ApplictionServiceImpl.java),需要在service层中加上
applicationService.addStudent(),deleteStudent(),updateStudent(),queryStudent()四个方法。
这时你需要更新service层的接口类ApplicationService.Java,加上这四个方法。然后再更新service层的实现类ApplicationServiceImpl,加上这四个方法,最后你发现这四个方法每个方法里都只有一句话(以addStudent()为例)
public int addStudent(Student student){
    return student.add();
}
这样是不是太傻了点,还不如在action中直接调用StudentDAO中的student.add()。
以上是我的个人看法,请各位指点





这么来讲好了 按你所说 在action中直接调用StudentDAO中的student.add()。 现在有客户A 客户B

客户A的需求是 addStudent 这个和你所说的情况一致

客户B的需求是 addStudent 前去加一个动作 将学生父母的信息也插入数据库

这时如果按照只调用DAO的方法的话,你需要从新建立一个action
CustomerBAction
再重新写一个DAO 因为这个DAO里要有添加父母的方法 student.addStudentAndParentInfo()。

CustomerBAction 去调用 student.addStudentAndParentInfo()。

这样加大了很多工作量

如果中间有service层的话 action始终用一个action
而调用的也是service接口 只要对接口注入不同的实现就可以满足 不同客户的需求了

知识要活学活用,要按照自己项目以后的发展趋势来搭设环境,别人家说什么就用什么。其实有时候javabean+jsp 也很好用啊,因为jsp不用重启服务 开发速度很快。我做小项目就是这种模式,以后小项目的更改也会很少,所以不用搭建的过于复杂。


补充:

entity和vo的不同还可以通过下边这个例子说明。如有user.java和userVO.java
user的属性为

private int id ; 
private String username ; 
private String password ;
而userVO的属性则可为:

private int id ; 
private String username ; 
private String password1 ;	//第一次输入密码
private String password2 ;	//确认密码
在表单验证时,password1和password2相同时才会被提交。这样不用改entity类,只需修改vo层即可。当然,这里的password1和password2也得写上get和set方法。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值