自己的项目:传统创建mapper,然后在相应的mapper方法上加对应的注解@Select、@Update诸如此类的方法,最后service层直接调用mapper。然后controller直接用service然后统一回复个result就结束了
公司的项目:
1、sql
sql都是封装好的,写在resource/sql-ext select id, company_code from sys_company where company_code in (:companyCodes)
(:companyCodes)代表传进的参数
其中我发现了有个在参数前面有个:符号,这是因为防止sql注入,还有提高性能。所以这样写的话,一般要在参数前面加:
总结:拆分得不能再拆分,好维护好修改
2、model
公司的实体类都是在model下。公司创建了一些基于@MappedSuperclass注解的model用于代码复用
《1》标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
《2》标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。
所以有很多model是extends ***Model(各式各样的通用属性)。如果不需要用到通用属性的话或者本身作为被通用的类也就是有@MappedSuperclass注解的类,就得implements Model //import com.chinaservices.jpa.Model
Model源码
public interface Model extends Serializable { void setCompanyId(Long var1); void setCreator(Long var1); void setCreateTime(Date var1); void setModifier(Long var1); void setModifyTime(Date var1); }
可以看出这是一种规范,也就意味着每个model都必须要有这些方法
总结:规范,复用再复用,省事儿
3、bean
bean文件夹下,会为条件创建相应的condition、为增加创建相应的item、为搜索创建相应的Query
例如:
其中
Condition extends PageCondition(如果不是PageCondition而是其他Condition,其原因也是因为复用属性,但最终还是会继承Condition)
//PageCondition里有3个参数,可以看出是用于分页
private Integer pageSize; private Integer pageNumber; private String orderBy;
Item implements Item
//Item里有2个属性,是为了规范,一定要加这2个属性
void setModifier(Long var1); void setModifyTime(Date var1);
Query implements Query
//Query啥都没有,不过估计是没有要规范的,但写出来还是因为代码规范
以上都是import com.chinaservices.jpa.*
Condition
用来写参数,例如
public class DispatchGpsCondition extends WmsPageCondition { private String startTime; private String endTime; private String terminalId; public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getEndTime() { return endTime; } public void setEndTime(String endTime) { this.endTime = endTime; } public String getTerminalId() { return terminalId; } public void setTerminalId(String terminalId) { this.terminalId = terminalId; } }
这段代码是为了查询GPS,其中sql中需要三个参数,一个是id还有2个分别是开始时间和结束时间
,咱们可以看看对应的sql文件便知
sql
select a.id, a.gps_time, a.terminal_id, a.lat, a.lng as lon from cs_gps_pack_${terminalId} a where a.gps_time >= :startTime and a.gps_time <= :endTime
Query
这个就无需贴出来了,因为它写的是查询表中需要查询到的数据,由于太多,不想发。格式还是一样,无非就是private 巴拉巴拉,然后getset。
Item
也是private巴拉巴拉加getset,它写的变量是需要更新或者新增的数据。
总结:拆分再拆分,好维护好拓展好****
4、Service
可以说Service是将bean和sql结合起来进行crud *** 作。
公司的Service 都是继承于WmsbaseService
public class WmsbaseService extends baseService { private static String PRIMARY_KEY = "id"; @Autowired protected CommonJpaRepository dao; @Autowired protected SqlExecutor sqlExecutor; publicboolean saveOrUpdate(Class modelClass, Item item, InsertPreSave preSave) { SessionUserInfo sessionUserInfo = SessionContext.getSessionUserInfo(); item.setModifier(sessionUserInfo.getUserId()); item.setModifyTime(new Date()); if (EmptyUtil.isEmpty(ClassUtil.getPropertyValue(item, PRIMARY_KEY))) { try { T model = modelClass.newInstance(); BeanUtil.copyProperties(item, model); model.setCreator(sessionUserInfo.getUserId()); model.setCreateTime(new Date()); model.setCompanyId(sessionUserInfo.getCompanyId()); preSave.accept(model); dao.insert(model); BeanUtil.copyProperties(model, item); } catch (Exception e) { logger.error(e.getMessage()); return false; } } else { dao.update(modelClass, item); } return true; } public boolean saveOrUpdate(Class extends Model> modelClass, Item item) { SessionUserInfo sessionUserInfo = SessionContext.getSessionUserInfo(); if(null == sessionUserInfo){ item.setModifier(-1L); }else { item.setModifier(sessionUserInfo.getUserId()); } item.setModifyTime(new Date()); if (EmptyUtil.isEmpty(ClassUtil.getPropertyValue(item, PRIMARY_KEY))) { try { Model model = (Model) modelClass.newInstance(); BeanUtil.copyProperties(item, model); if(null == sessionUserInfo){ model.setCreator(-1L); } else { model.setCreator(sessionUserInfo.getUserId()); model.setCompanyId(sessionUserInfo.getCompanyId()); } model.setCreateTime(new Date()); dao.insert(model); BeanUtil.copyProperties(model, item); } catch (Exception e) { logger.error(e.getMessage()); return false; } } else { dao.update(modelClass, item); } return true; } public void preSave(Item item) { SessionUserInfo sessionUserInfo = SessionContext.getSessionUserInfo(); if(null == sessionUserInfo){ item.setModifier(-1L); }else { item.setModifier(sessionUserInfo.getUserId()); } item.setModifyTime(new Date()); } public void preSave(Model model) { SessionUserInfo sessionUserInfo = SessionContext.getSessionUserInfo(); if (EmptyUtil.isNotEmpty(sessionUserInfo)){ model.setModifier(sessionUserInfo.getUserId()); }else { model.setModifier(-1L); } model.setModifyTime(new Date()); if (EmptyUtil.isEmpty(ClassUtil.getPropertyValue(model, PRIMARY_KEY))) { if (EmptyUtil.isNotEmpty(sessionUserInfo)){ model.setCreator(sessionUserInfo.getUserId()); model.setCompanyId(sessionUserInfo.getCompanyId()); }else { model.setCreator(-1L); } model.setCreateTime(new Date()); } } //接口用preSave,没有session public void ediPreSave(Model model) { model.setModifier(1L); model.setModifyTime(new Date()); if (EmptyUtil.isEmpty(ClassUtil.getPropertyValue(model, PRIMARY_KEY))) { model.setCreator(1L); model.setCreateTime(new Date()); } } }
saveOrUpdate():见名知其意,保存或者更新。有2种方式,一个是三个参数,一个是两个参数。其中因为是需求不一样,所以有不同的方法。很容易发现这两个方法的参数之中的区别就是多了一个InsertPreSave
preSave.accept(model);
看看源码
@FunctionalInterface public interface InsertPreSave{ void accept(T t); default Consumer andThen(Consumer super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
里面只有一个方法Object.requireNonNull(),这个方法只是进行了一个简单的判断, 如果所要判断的元素为 null, 则返回空指针异常 NullPointerException, 否则直接返回对应的对象。
之所以多了个这个参数的原因是:
首先, 从这个方法的名称可以看出, 这个方法使用的场景是, 我们使用一个对象的方法时, 正常的运行状态应该能保证这个对象的引用非空, 如果这个对象为空了, 那一定是其他某个地方出错了, 所以我们应该抛出一个异常, 我们不应该在这里处理这个非空异常.
其次, 这里涉及到一个很重要的编程思想, 就是 Fail-fast 思想, 翻译过来就是, 让错误尽可能早的出现, 不要等到我们很多工作执行到一半之后才抛出异常, 这样很可能使得一部分变量处于异常状态, 出现更多的错误. 这也是 requireNonNull 这个方法的设计思想, 让错误尽早出现. 使用这个方法, 我们明确的抛出异常, 发生错误时, 我们立刻抛出异常.
说白了就是debug会更明确,更简洁
下面还有两个preSave()方法,两者差别又是参数不一样
带Item的preSave()方法是用EmptyUtil.isNotEmpty(sessionUserInfo)判断session是否存在,不存在则返回-1,存在则把用户id存入item的某个值中
带Model的preSave()方法与上一个的不同地方在于多了2个判断,首先是if(EmptyUtil.isEmpty(ClassUtil.getPropertyValue(model, PRIMARY_KEY)))
这个判断是用于判断类的方法,通俗来讲就是通过方法的修饰符(public/protected/private/package),来判断方法的调用者是否可以访问该方法
其次是EmptyUtil.isNotEmpty(sessionUserInfo)再次判断session是否存在,如果存在则设置用户信息以及公司的信息给model,我猜测应该是很重要的信息,所以需要多重判断
最后一个方法ediPreSave()方法已经很明了了,就是没有session的情况,也就是只用判断if(EmptyUtil.isEmpty(ClassUtil.getPropertyValue(model, PRIMARY_KEY)))即可,判断通过就赋值。
同时我们发现,WmsbaseService又继承于LoggerFactory,点进去看了一下源码,里面只有一个方法
public abstract class baseService { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); public baseService() { } }
查了一下,说是使用指定类初始化日志对象,在日志输出的时候,可以打印出日志信息所在类
如:Logger logger = LoggerFactory.getLogger(Actions.class);
logger.debug("日志信息");
将会打印出: Actions : 日志信息
WmsbaseService还有2个开头的
@Autowired protected CommonJpaRepository dao; @Autowired protected SqlExecutor sqlExecutor;
其中CommonJpaRepository即公司封装好的JpaRepository,这用到了spring data jpa的知识,也就意味着里面的方法可以直接 *** 作数据库
而SqlExecutor则是sql执行器,也是执行数据库 *** 作的
看了公司的某个Service类
(1)分页 *** 作和复杂查询的 *** 作使用SqlExecutor里的方法
(2)增加更新 *** 作则用WmsbaseService里面的方法
(3)删除简单查询不需要分页还有校验判断之类的用CommonJpaRepository里的方法
其实还是得根据情况来用方法。。。。。。
5、Controller
在每个方法的上面还多加一个注解,例如
@Log(model = "运输管理", description = "装货明细分页查询")
说白了就是加了日志
方法的类型如果是自己的项目是Result,而公司的则是 ResponseData<?>,当然这个也不是固定的,还是得看情况而言
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)