JAVA框架封装(二):整体设计

编写一个程序,最大的难点在于开始的设计,设计完了,那么基本上就完成了一大半。这指的是写应用系统,因为编码并不需要很多时间,大部分的工作都有框架帮你完成。而现在要写的是框架,并不是应用系统,但也要有开始的设计阶段,只不过,一开始的设计,不会很全面,随着编码的进行,会不断的添加新东西进来,使得框架越来越完善,功能也越来越多。所以,在最开始的起步阶段,选择一个相对简单的功能,作为切入点,这就比较重要了。不要想着,一开始写,就要把这个框架写得很完美,很通用,又要考虑这,又要考虑那。结果就是,考虑的太多,却迟迟没法下手。结果可能就是还没开始就难产了。而我选择的切入点,就是最简单的类与表的映射。在java中,类没有继承关系,在数据库中,表没有关联关系,也就是单张表的情况。基于此,实现通用的增删查改,这个都已经实现了。注解扫描器实现了,拦截器也简单地实现了。那么接下来的开发计划有:

1. 多表关联的实现

2. 分页的实现

3. java类有继承关系的实现

4. 数据库事务的引入,连接池的使用

5. 自动建表的实现

6. 多线程的使用

7. 与一些框架、工具的整合,比如spring

8. 扩展功能的开发,比如通用上传文件,下载文件的方法实现,权限管理等

实际上,在这些计划中,有些都已经开发好了,比有使用连接池,几分钟就搞定了,引入jar包、配置文件,再修改两行代码,连接池就使用上了,主要是今天想看一下多表连接查询的性能,于是就把连接池配置了起来。连接5张表进行查询,查询10W次,花费时间15秒多一点,也就是1毫秒可以查询6次,当然我现在10W次的查询是一模一样的,而且数据库中也就几条数据,不能说明什么。通用下载方法(导出数据为Excel)也写好了,只是没有整合。

说了这么多,那这个框架,到底是咋样的呢?这里,就以我做测试用的Goods类来作为例子说明:

package king.test.entry;

import java.util.List;

import org.kingeasy.annotation.ColumnName;
import org.kingeasy.annotation.Immutable;
import org.kingeasy.annotation.Mapping;
import org.kingeasy.annotation.NoDeletion;
import org.kingeasy.annotation.NoRepeat;
import org.kingeasy.annotation.PrimaryKey;
import org.kingeasy.annotation.RoadMapping;
import org.kingeasy.annotation.Search;
import org.kingeasy.annotation.Statistic;
import org.kingeasy.annotation.TableName;
import org.kingeasy.base.Service;
import org.kingeasy.base.Statistics;
import org.kingeasy.base.TableRelation;

/**
 * 路径注解
 * 在框架里,有一个注解扫描器,通过扫描,会把指定包下的所有类的这个注解扫描出来,加入到一个map中。
 * 当有一个请求过来,则会有一个拦截器把请求拦截下来,拦截器会把URI后面两部分截取出来,倒数第二部分,
 * 会与这个注解的value进行匹配,匹配上,则说明请求,是要访问这个类的,URI的最后部分,则是方法名,
 * 在框架内封装了一系列通用的方法,要调用哪个方法,就是通过URI的最后部分来指定。
 * 例如:请求的URI以“/goods/search”结尾,那么就会调用框架内的search方法,方法关联的类就是这个类,
 * 即:king.test.entry.Goods
 * 当然,这个注解不是必须的,如果没有加这个注解,则默认为类的简要名称,即goods,不区分大小写
 */
@RoadMapping("goods")

/**
 * 表名注解
 * 指定数据库中与这个类关联的表的表名
 * 这个注解,并不是必须,如果没有添加,则会以类的简要名称,作为表名来映射,
 * 意味着,只有类名与数据库中表名不一致时,才需要添加这个注解
 * 数据库是不区分大小写的,所以goods和Goods,在数据库中是一样的
 */
@TableName("goods")
public class Goods {
	
	/**
	 * 主键注解
	 * 指定这个类的主键,一个类,必须要有一个主键
	 * 如果字段名与数据库的列名不一致,则还需要添加value来指名数据中的列名
	 * 如@PrimaryKey("goods_id"),则类的字段,与数据库中的goods_id进行关联
	 */
	@PrimaryKey

	/**
	 * 聚合函数注解,这是默认模式,具体的可以看后面的注释
	 */
	@Statistic

	/**
	 * 查询注解
	 * param为前端查询时,使用的键名,即表单元素的name的值
	 * exp为查询条件的关系表达式,注意"?"不能省略,通用方法里的所有sql都是使用的预编译
	 * 主要是考虑一些复杂的查询,比如模糊查询,不好确定"?"的位置,所以还是由用户自己写这个"?"
	 * 如果param与类的字段名一致,则param,可以不写
	 * 如果exp的值为"=?",也可以省略不写
	 */
	@Search(param="goodsId", exp="=?")
	private int id;

	/**
	 * 不可重复注解
	 * 在插入和修改数据的时候,有些字段是不可以重复的,则添加这个注解
	 * 注解的value,为提示语,如果出现了重复,则会把提示语响应给前端,前端可以直接拿这个作为提示语显示给用户
	 * 这个后期会有功能的扩充
	 */
	@NoRepeat("商品名称重复")
	@Search(param="goods_name", exp="LIKE CONCAT('%', ?, '%')")
	private String name;

	/**
	 * 数据库列名注解
	 * 当类的字段名与数据中的列名不一致时,使用这个注解
	 * 如果一样,可以省略这个注解
	 */
	@ColumnName("image_addr")
	private String image_addr;

	/**
	 * 限制修改注解
	 * 在修改数据的时候,对于添加了这个注解的字段,会忽略这个字段的值
	 * 比如:现在price字段添加了这个注解,那么在调用修改商品数据的接口时,
	 * 即使传了price的值,也会直接忽略掉
	 */
	@Immutable
	private double price;
	@Search(param="minStock", exp=">=?")
	@Search(param="maxStock", exp="<=?")

	/**
	 * 聚合函数注解
	 * 添加这个注解,可以对数据库中对应的列进行聚合,一张表,可以有多个列进行聚合
	 * 聚合的结果,会放到一个map中
	 * key用于指定放入map中时的key值,默认值为"total"
	 * statistic指定用什么聚合函数。取值有COUNT、SUM、AVG、MAX、MIN,默认值为COUNT
	 * handleNull指定是否处理null值,默认为false,即不处理null值
	 */
	@Statistic(key="stocks", statistic=Statistics.SUM, handleNull=false)
	private int stock;

	/**
	 * 多表映射注解
	 * 用于描述多张表的关联关系
	 * tableRelation有四个取值:ONE_TO_ONE、ONE_TO_MANY、MANY_TO_ONE、MANY_TO_MANY
	 * value是一个数组,根据tableRelation的值不同,含义也不同
	 * 当tableRelation为MANY_TO_MANY时,value里的第一个值为中间表的表名,第二个值为中间表与当前类(表)主键关联的字段名,第三个值为中间表与另一个类(表)主键关联的字段名
	 * 注意:只要两张表关联时,使用了中间表,就是MANY_TO_MANY,即使具体的业务不是多对多
	 * 现在也只实现了MANY_TO_MANY的查询
	 * 当tableRelation为ONE_TO_MANY时,value为空数组,可以省略
	 * 当tableRelation为MANY_TO_ONE时,value里只有一个值,即另一个表的主键关联当前表中的列名
	 * 当tableRelation为ONE_TO_ONE时,value里只有一个值,即另一个表,与本表关联的列名
	 */
	@Mapping(tableRelation=TableRelation.MANY_TO_MANY, value={"goods_category_mapping", "goods_id", "category_id"})

	/**
	 * 限制删除注解
	 * 这个注解通常用于关联其它类的字段,当该类有关联另一个类的数据时,限制用户不能删除
	 * 注解的value为提示语,value里面,允许显示另一个类的一个字段的值
	 * 比如,现在的这个注解,当商品关联了一个分类时,则删除商品时,就会不允许删除,提示语中的{{category_name}},
	 * 会替换成关联的商品分类的分类名,如果关联多个分类,则多个分类的名称,以英文的逗号(暂定)分隔显示
	 */
	@NoDeletion("该商品关联了分类{{category_name}},不允许删除")
	private List<Item> items;
	@Mapping(tableRelation=TableRelation.MANY_TO_MANY, value={"goods_group_mapping", "goods_id", "group_id"})
	private List<Group> groups;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getImage_addr(){
		return image_addr;
	}
	public void setImage_addr(String image_addr){
		this.image_addr = image_addr;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public int getStock(){
		return stock;
	}
	public void setStock(int stock){
		this.stock = stock;
	}
	public List<Item> getItems(){
		Service.getRelationEntry(this);
		return items;
	}
	public void setItems(List<Item> items){
		this.items = items;
	}
	public List<Group> getGroups(){
		Service.getRelationEntry(this);
		return groups;
	}
	public void setGroups(List<Group> groups){
		this.groups = groups;
	}
	@Override
	public String toString() {
		return "Goods [id=" + id + ", name=" + name + ", image_addr=" + image_addr + ", price=" 
				+ price + ", stock=" + stock + ", \nitems=" + getItems() + ", \ngroups=" + getGroups() + "]";
	}
	
}

这一个java类里面,就包含了我现阶段所定义的所有注解,当然有些注解加上,只是为了说明有这么一个注解,及这个注解是做什么用的,并不是具体义务的反映。从这些注解里面,就可以大致地看出,整个框架,有哪些功能,以及整个框架是怎么运作的。那么,接下来,就是要去定义这些注解,以及实现这些注解的功能了。

欢迎加入测试群:91425817,一起讨论测试的那此事。

发布了47 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/kingzhsh/article/details/97234382