简单的Web项目

系统架构

在这里插入图片描述
在这里插入图片描述1. Controller 控制器层:业务分发、返回业务处理结果
2. View 视图层:展示数据
3. Model 模型层:包装起来的数据,本质是数据
4. Service 业务层:业务逻辑处理
5. Dao 数据库访问层:与数据库通信

数据库设计

在这里插入图片描述

访问流程图

在这里插入图片描述

通信协议制定

1.获取表的静态数据:
{account:用户账号
tableName:表名,
tableHead:[[属性名,列名,input类型,…]],
opUrl:编辑链接}

说明:
属性名对应数据对象的属性名、列名是展示给用户看的列名
编辑链接告诉试图层要不要编辑表的功能

视图层根据这些信息动态生成不同数据表的展示页面

2.查询表:
请求:{pageSize:页大小,pageIndex:第几页,url}
返回:{recordNum:记录数,records:[数据对象数组]}

3.编辑表:
请求:{url,op:(增/删/改),属性名:属性值,属性名:属性值,…}
返回:{msg:成功与否}

编辑前端页面


在这里插入图片描述

实现相关工具类

JdbcUtils

使用条件
数据表id设置为 id String
数据列表名及顺序与对象属性名一致
在这里插入图片描述
1.<T> List<T> queryBySql(String sql,Class<T> type)
功能:根据sql语句查询,并将查询结果包装成传入的type类型对象,再放入list集合并返回

其中用到BeanUtils类的<T> T packBean(String[] values, Class<T> type)方法,用于将values属性值数组包装到type类型对象中并返回

public static <T> List<T> queryBySql(String sql,Class<T> type) 
			throws ReflectiveOperationException{
	ArrayList<T> list = new ArrayList<>();
	Connection conn = ConnectionPool.get(); //连接池中获取连接
 	try(
		Statement stmt = conn.createStatement();
		ResultSet rs = stmt.executeQuery(sql);
	){
		if(!rs.next()) {//若无结果,返回集合赋空
			list = null;
		}else{
		    do {//包装查询结果为对象,并放入集合
			    list.add(BeanUtils.packBean(
				   getFields(rs,type.getDeclaredFields()),type));
		    }while(rs.next());
		}
	}catch(SQLException e) {
		e.printStackTrace();
	}finally {
		ConnectionPool.close(conn);   //连接返回池中
	}
	return list;
}

2.String[] getFields(ResultSet rs, Field[] fields)
功能:从ResultSet对象中取得对应Filed对象的属性值的字符串格式

public static String[] getFields(ResultSet rs, Field[] fields) throws SQLException {
	String[] values = new String[fields.length];
	for (int i=0;i<fields.length;i++) {
		fields[i].setAccessible(true);
		values[i] = rs.getString(fields[i].getName());
	}
	return values;
}

其他方法主要围绕queryBySql(String)、updateBySql(String)经行扩展

BeanUtils

在这里插入图片描述
功能:主要是将String类型的属性值转化为Field.getType()类型的属性值并设置进对象

1.<T> T packBean(String[] values, Class<T> type)
功能:将values数组的值包装进type类型对象中
使用条件:数组中属性值顺序应与对象属性定义顺序一致

public static <T> T packBean(String[] values, Class<T> type) 
			throws ReflectiveOperationException {
		T obj = type.newInstance();
		Field[] fields = type.getDeclaredFields();
		for(int i=0;i<values.length;i++) {
			if(values[i]==null) {//若字符串值为空,开始下次循环
				continue;
			}
			fields[i].setAccessible(true);
			Object value = null;
			try {//将字符串值转化为属性对应的类型
				value = getRealValue(fields[i].getType(),values[i]);
				fields[i].set(obj, value);//设置属性值
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
		return obj;
	}

2.Object getRealValue(Class<?> type,String value)
功能:将value转化为type类型,若无法转化抛出异常

public static Object getRealValue(Class<?> type,String value) throws Exception{
		Object obj = value;
		if(type==int.class||type==Integer.class) {
			obj = Integer.valueOf(value);
		}else if(type==String.class) {
		}else if(type==BigDecimal.class) {
			obj = new BigDecimal(value);
		}else if(type==Date.class) {
			obj = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value);
		}else if(type==boolean.class||type==Boolean.class) {
			obj = (value.equals("1")||value.equals("true"))?true:false;
		}else if(type==double.class||type==Double.class) {
			obj = Double.valueOf(value);
		}else if(type==byte.class||type==Byte.class) {
			obj = Byte.valueOf(value);
		}else if(type==long.class||type==Long.class) {
			obj = Long.valueOf(value);
		}else if(type==short.class||type==Short.class) {
			obj = Short.valueOf(value);
		}else if(type==float.class||type==Float.class) {
			obj = Float.valueOf(value);
		}
		return obj;
	}

3.<T> T packBean(Map<String, String[]> paramMap,Class<T> type)
功能:将Map<属性名,字符串属性值>集合包装成对应type类型对象

public static <T> T packBean(Map<String, String[]> paramMap,
			Class<T> type) throws ReflectiveOperationException{
		T obj = type.newInstance();
		Set<Entry<String, String[]>> entrys = paramMap.entrySet();
		for (Entry<String, String[]> entry: entrys) {
			Field field = null;
			try {//获取该类型对象对应属性名的Field对象,若无,开始下次循环
				field = type.getDeclaredField(entry.getKey());
			} catch (ReflectiveOperationException e) {
				continue;
			}
			//若字符串属性值为空可以不设置,开始下次循环
			if(entry.getValue()[0]==null) {
				continue;
			}
			field.setAccessible(true);
			Object value = null;
			try {//字符串属性值不为空,设置属性值
				value = getRealValue(field.getType(),entry.getValue()[0]);
				field.set(obj, value);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return obj;
	}

BaseController、BaseService、BaseDao、BaseBean

在这里插入图片描述
每个数据库表都对应一个BaseBean的子类,也有对应的BaseDao、BaseService的子类
edit方法、getJsonData方法操作的数据库表决定与BaseController的子类控制器传入edit方法、getJsonData方法的service对象
也就是只要数据库表对应的模型层、数据库访问层、业务层继承对应基类,即可实现基本的增删改查功能

Basecontroller

1.doPost调用doGet方法

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
			throws ServletException, IOException {
		doGet(req, resp);
	}

2.doGet

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
		throws ServletException, IOException {
	req.setCharacterEncoding("utf-8");
	resp.setCharacterEncoding("utf-8");
	String uri = req.getRequestURI();
	int startIndex = uri.lastIndexOf("/")+1;
	String target = uri.substring(startIndex);//获得请求目标
	try {//反射调用目标方法处理请求
		Method method = this.getClass().getDeclaredMethod(target, 
				HttpServletRequest.class,HttpServletResponse.class);
		String command = (String) method.invoke(this, req,resp);
		doOver(req,resp,command);//根据返回信息响应浏览器
	} catch (ReflectiveOperationException e) {
		e.printStackTrace();
		resp.sendError(404);
	} 
}

3.doOver响应
command格式为: 指令:信息

private void doOver(HttpServletRequest req, HttpServletResponse resp,
			String command) throws ServletException, IOException {
		String[] arr = command.split(":", 2);
		switch (arr[0]) {
		case "forward":
			req.getRequestDispatcher(arr[1]).forward(req, resp);
			break;
		case "redirect":
			resp.sendRedirect(arr[1]);
			break;
		case "error":
			resp.sendError(Integer.valueOf(arr[1]));
			break;
		case "data":
			resp.getOutputStream().write(arr[1].getBytes());
			break;
		default:
			break;
		}
	}

4.getJsonData 获取json格式的数据表数据
传入的service不同,获取的数据表数据不同

protected <T extends BaseBean> String getJsonData(HttpServletRequest req,BaseService<T> service) {
		Map<String,String[]> paramMap = req.getParameterMap();
		String vagueSql = req.getParameter("vagueSql");
		Page page = null;
		try {
			page = BeanUtils.packBean(paramMap, Page.class);
		} catch (ReflectiveOperationException e) {
			e.printStackTrace();
		}
		//根据条件查询数据表,并将结果包装为list集合
		List<T> list = service.querySome(vagueSql, page);
		//查询记录数
		int recordNum = service.queryCount(vagueSql);
		JSONObject jsonData = new JSONObject();
		jsonData.put("recordNum", recordNum);
		jsonData.put("records", list);
		return jsonData.toJSONString();
	}

5.edit编辑数据表

protected <T extends BaseBean> String edit(BaseService<T> service,String command,T obj) {
		String ret = "";
		switch (command) {
		case "modify":
		    //修改数据库中id与obj.id相同的记录,并返回修改结果
			ret = (service.modify(obj))?"修改成功!":"修改失败!";
			break;
		case "add":
	        //添加obj到数据库,并返回添加结果
			ret = (service.add(obj))?"添加成功!":"添加失败!";
			break;
		case "del":
		    //删除数据库中id与obj.id相同的记录,并返回删除结果
			ret = (service.del(obj))?"删除成功!":"删除失败!";
			break;
		default:
			break;
		}
		return ret;
	}
BaseDao
public class BaseDao<T extends BaseBean> {
	
	protected Class<T> targetClass; //数据表对应的对象类型
	protected String tableName;     //数据表名
	
	protected BaseDao(String tableName,Class<T> targetClass) {
		this.tableName = tableName;
		this.targetClass = targetClass;
	}
	//根据id查询记录
	public T queryById(String id) {
		try {
			return (T) JdbcUtils.getEntryById(tableName, id, targetClass);
		} catch (ReflectiveOperationException e) {
			e.printStackTrace();
		}
		return null;
	}
	//插入记录
	public synchronized boolean insert(T bean) {
		if(queryById(bean.getId())==null) {
			try {
				return JdbcUtils.insertEntry(bean, tableName);
			} catch (ReflectiveOperationException e) {
				e.printStackTrace();
			}
		}
		return false;
	}
	//删除记录
	public boolean delete(T bean) {
		return JdbcUtils.delEntryById(tableName, bean.getId());
	}
	//查询记录
	public List<T> querySome(String vagueSql, int limitA, int limitB) {
		List<T> list = null;
		try {
			list = JdbcUtils.querySome(
					tableName, targetClass,vagueSql,limitA,limitB);
		} catch (ReflectiveOperationException e) {
			e.printStackTrace();
		}
		return list;
	}
	//查询记录数
	public int queryCount(String vagueSql) {
		String sql = "select count(*) from "+tableName+vagueSql;
		return JdbcUtils.queryCount(sql);
	}
	//修改数据库,实际是替换数据库中id与bean.id相同的记录
	public synchronized boolean modify(T bean) {
		T dbBean;
		if((dbBean=queryById(bean.getId())) != null) {
			delete(dbBean);
			try {
				return JdbcUtils.insertEntry(bean, tableName);
			} catch (ReflectiveOperationException e) {
				e.printStackTrace();
			} 
		}
		return false;
	}
	//查询所有记录
	public List<T> queryAll() {
		List<T> list = null;
		try {
			list = JdbcUtils.queryAll(tableName,targetClass);
		} catch (ReflectiveOperationException e) {
			e.printStackTrace();
		}
		return list;
	}
}
BaseService
public class BaseService<T extends BaseBean> {
	protected BaseDao<T> dao;           //对应的dao对象
	protected Class<T> targetClass;     //数据表对应的对象类型
	
	protected BaseService(BaseDao<T> dao,Class<T> targetClass){
		this.dao = dao;
		this.targetClass = targetClass;
	}
	//查询一些记录
	public List<T> querySome(String vagueSql, Page page) {
		List<T> list = null;
		if(vagueSql==null) {
			vagueSql = "";
		}
		list = dao.querySome(vagueSql,page.getLimitA(), page.getPageSize());
		return list;
	}
	//查询记录数量
	public int queryCount(String vagueSql) {
		if(vagueSql==null) {
			vagueSql = "";
		}
		return dao.queryCount(vagueSql);
	}
	//修改记录
	public boolean modify(T bean) {
		if(bean.getId()==null||bean.getId().equals("")) {
			return false;
		}
		return dao.modify(bean);
	}
	//添加记录
	public boolean add(T bean) {
		if(bean.getId()==null||bean.getId().equals("")) {
			bean.setId(randomId());
		}
		return dao.insert(bean);
	}
	//生成随机Id
	public String randomId() {
		return UUID.randomUUID().toString().replaceAll("-", "");
	}
	//删除记录
	public boolean del(T bean) {
		if(bean.getId()==null||bean.getId().equals("")) {
			return false;
		}
		return dao.delete(bean);
	}
}

总结

1.确立需求,并分析需求建立好的数据库非常重要,后期修改数据库是非常麻烦的事情
2.提前定义通信流程、视图层与控制器层的通信协议,能让项目编写过程更加顺畅
3.善于辨别必要的通信数据可以更好的制定通信协议
4.编写好的工具类能使项目编写过程方便很多
5.根据相关类的共性并利用映射与泛型提取出基类,可以大大降低代码耦合度并使后续扩张简单
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值