一个基于SSM的CRUD的标准写法
CRUD即CREATE,READ,UPDATE,DELETE的首字母的合写,意思是增读改删。前人为了便于发音和理解,改为增删改查。
CRUD基本上是软件开发中中相当部分功能的最小功能模块构成,虽然软件的功能并不总是CRUD,但对于信息的操作就只有这四个了。
我们现在还是这么称呼,一个方面是因为大部分的功能要求和此类似,其次是因为这个名称还不错。
原则上来说CRUD功能很简单,简单到一个得到训练的初中生都能够做得很好,如果不是考虑到英文,可以把这个学历下降到小学,更具体是5年级以上。
我总是喜欢那样的人:有自知之明,热爱学习,努力学习,不耻相师。
一、crud总体是简单的
通常来说业务虽然简单,但又不是那么简单。
软件设计中,表、对象设计本质上就是对客观世界的模仿/映射。我们的很多灵感完全来源于客观世界,少数来自于数学。
现实的世界并不简单,事物之间通常是有勾连的。既然事物有勾连,那么软件设计中的对象和表也理应体现这种关联。
所以,一个crud,虽然很简单,也不是那么简单,但终归是简单的。
在软件工程师工作中,比CRUD简单的活并不容易找到。
如果一个工程师觉得这个也困难,那么毫无疑问是极其不合格。他要么反省并努力,要么换一行,避免徒增笑话。
反省和努力应该是我们大部分人的自觉和选择。
二、基本的例子
现在我们写代码已经变得很轻松,至少对于一些简单的功能是可以那么说的。为了便于理解,这里举例下。
有个需求如下:
有个积分规则,规则有点小复杂,和时间、客户等级、消费金额、商品分类等都有关系,简而言之,就是让客户弄不清楚,但好像又有很多优惠一样。
所以,设计师设计了至少5张表,用来存储积分设置,涵盖规则基本信息,各种计算规则,这五张表依次是:
1.ruleBase --规则基本信息,id为自增主键
2.rule_time_setting-规则时间设置,外键rule_id指向ruleBase
3.rule_customer_setting-客户设置,外键rule_id指向ruleBase
4.rule_goods_setting-商品设置,外键rule_id指向ruleBase
5.rule_amount_setting-金额设置,外键rule_id指向ruleBase
此外还有两张表:
6.customer-客户表,外键rule_id只想ruleBase
7.customer_reward_point_dtl-客户积分获取明细,外键customer_id,rule_id分别指向customer,ruleBase。
rule_*表依赖于ruleBase存在。当规则删除的时候,有关的数据应该删除掉。
编码工程师在理解需求和设计之后,就可以编码了。
如果写得正确,大概是这样的(ruleBase,基于ssm编写):
@Service public class RuleBaseServiceImpl implements IRuleBaseService { @Autowired private RuleBaseMapper ruleBaseMapper; /** * 查询积分规则基本信息 * * @param id 积分规则基本信息主键 * @return 积分规则基本信息 */ @Override public RuleBase selectRuleBaseById(Long id) { return ruleBaseMapper.selectRuleBaseById(id); } /** * 查询积分规则基本信息列表 * * @param RuleBase 积分规则基本信息 * @return 积分规则基本信息 */ @Override public List<RuleBase> selectRuleBaseList(RuleBase RuleBase) { return ruleBaseMapper.selectRuleBaseList(RuleBase); } /** * 新增积分规则基本信息 * * @param RuleBase 积分规则基本信息 * @return 结果 */ @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class) @Override public int insertRuleBase(RuleBase RuleBase) { //TODO::检测积分规则名称是否重复,如果重复则抛出异常 RuleBase.setCreateBy(SecurityUtils.getUsername()); RuleBase.setCreateTime(DateUtils.getNowDate()); return ruleBaseMapper.insertRuleBase(RuleBase); } /** * 批量新增积分规则基本信息 * * @param RuleBaseList 积分规则基本信息 * @return 结果 */ @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class) @Override public int batchInsertRuleBase(List<RuleBase> RuleBaseList) { //TODO::检测积分规则名称是否重复,如果重复则抛出异常 for(RuleBase RuleBase : RuleBaseList){ RuleBase.setCreateBy(SecurityUtils.getUsername()); RuleBase.setCreateTime(DateUtils.getNowDate()); } return ruleBaseMapper.batchInsertRuleBase(RuleBaseList); } /** * 修改积分规则基本信息 * * @param RuleBase 积分规则基本信息 * @return 结果 */ @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class) @Override public int updateRuleBase(RuleBase RuleBase) { //TODO::检测积分规则名称是否重复,如果重复则抛出异常 return ruleBaseMapper.updateRuleBase(RuleBase); } /** * 批量新增或更新 积分规则基本信息 * * @param RuleBaseList 积分规则基本信息list * @return 结果 */ @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class) @Override public int insertOrUpdateBatch(List<RuleBase> RuleBaseList) { //TODO::检测积分规则名称是否重复,如果重复则抛出异常 return ruleBaseMapper.insertOrUpdateBatch(RuleBaseList); } /** * 批量删除积分规则基本信息 * * @param ids 需要删除的积分规则基本信息主键 * @return 结果 */ @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class) @Override public int deleteRuleBaseByIds(Long[] ids) { //TODO::检测积分规则是否被客户引用,如果被应用抛出异常,提示“已经被引用,不能删除” ruleBaseMapper.deleteRuleBaseByIds(ids); } /** * 删除积分规则基本信息信息 * * @param id 积分规则基本信息主键 * @return 结果 */ @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,rollbackFor=Exception.class) @Override public int deleteRuleBaseById(Long id) { //TODO::检测积分规则是否被客户引用,如果被应用抛出异常,提示“已经被引用,不能删除” return ruleBaseMapper.deleteRuleBaseById(id); } }
有的组织,或者某些业务可能不要求事务,或者添加实现事务的方式不一样,那么可以不需要如此写。不过这仅仅就是一个示例。
其余的几个略,不要浪费我们大家的时间。
三、经验
如果是有经验的负责编码的程序员(通常做过一两次就应该有),一看就知道应该如何写代码,大体过程值这样的:
1.使用工具快速生成各个表的crud代码(最基本的),这个过程可能就是1,2个小时左右
2.为各个crud添加判断是否被依赖,删除子表的有关代码,大概耗费2~3个小时
3.为各个具体的业务service添加上事务注解@Transactional(如果有别的偏好也可以,总之务必确保涉及到insert,delete,update的操作有事务).,大概几分钟。
有的时候,直接在代码生成模板中设置,甚至都不需要这一步。
4.处理控制器异常--主要是为异常给出合理和准确的异常描述
5.其它一些工作,例如数据初始化,给类和方法添加一些合适注释
6.协助前端工程师完成前端的编码
以上步骤1~5,理想情况下,可能就是一个上午的事情,多了就是一天的活,极少会需要2天甚至更多时间。
其中第1个步骤很关键:使用工具自动生成绝大部分代码。
注:上面步骤的时间估计,是基于前文例子的设计。
代码好像很多,其实工程师需要写的就没有几行代码(因为大部分代码是自动生成的)。
例子中,工作量一大部分在设计上,整个工作稍微有点技术含量的就是表设计和功能设计。
编码本上并没有什么技术含量(相对而言)
属于编码工程师要重点掌握一些技术:
- 数据库基本知识和表设计
- 软件设计基本理论
- spring的基础知识
- java基础知识
- 熟练使用ide(eclipse、idea、netbean、vscode中的一种或者多种)
这种规则和要求对于其它语言是类似的。当我们追求效率和效果平衡的时候,一般只能这么做。
四、小节
是不是很简单?只要花费一些心思、时间,那么做一个会CRUD的工程师还是很简单的,难度比我们学会拼音还低得多。
对于受过正规软件工程训练的人而言,掌握这一套方法可能就是2~3天的时间。
企业应该加强工具的学习和使用,才能大大提升工作效率。