1.报销管理-添加报销单-业务层
(1)在报销主表和明细表中都有一个字段叫expid,这个字段在数据库中是利用序列获取的,但是在业务层中,我们要控制主表和明细表的expid一致,所以要先获取expid赋值给主表和明细表,那么这个expid的值怎么得到呢?
通过获取序列的下一个值
2.报销管理-添加报销单-DAO层代码
(1)在我们的逻辑中,要向主表添加数据,要向明细表添加数据,但是假如在向明细表添加数据的过程中,出现异常了,那么程序就中断了,但是主表的数据被添加进去了,这个问题要怎么解决呢?
将多个操作视为一个事务,主要方法是将dao层的操作上升到业务层
(2)在我们目前的代码中,当添加明细出现问题的时候,页面还是会跳转到添加成功页面,这个问题怎么解决呢?
向上抛出异常
(3)现在的代码中,会出现另一个问题:主表数据添加成功,明细表数据添加失败,但是这些操作肯定是要么都成功,要么都失败的,那么这个问题怎么解决呢?
将多个操作视为一个事务,主要方法是将dao层的操作上升到业务层
3.报销管理-使用ThreadLocal实现业务层事务1
(1)说明ThreadLocal的作用?
用来存放我们connection变量,可以保证同一个线程中,不同方法,不同的层次操作使用的都是同一个connection
4.报销管理-使用ThreadLocal实现业务层事务2
(1)如何保证DBUtils工具类中getConnection方法获取到的Connection对象是一个呢?
创建ThreadLocal,并将我们创建的connection存放于ThreadLocal中,
(2)在DBUtils中是否要将Connection关闭呢?那要在什么时候关闭?
不需要,要在业务层所有的事务结束之后关闭connection
5.报销管理-待审报销单
(1)简述待审报销的思路?
当浏览器发送待审报销单的请求时,servlet处理请求,调用业务层的查询待审报销单的方法,传入从session中获取的登录人的id,业务层调用dao层方法,访问数据库,将查询结果返回给servlet层,然后放在request中,请求转发到页面,页面进行显示
(2)如何查询的是不是下一级审批人是当前登录人的信息?
我们从session中获取登录人的id,然后在数据库根据下一个审批人作为查询的条件
标题6.我要查询的是不是下一级审批人是当前登录人的信息?
我们从session中获取登录人的id,然后在数据库根据下一个审批人作为查询的条件
(1)根据业务流程图,请用文字详细描述报销流程。
根据报销单状态,有通过,拒绝,打回,
判断当前需要报销的金额,如果金额小于2500,直接由上级审核即可
如果当前报销的金额大于2500,直接上级审核过后,还要传到当前审核人的上级,要经由总裁审核
最终审核过后的报销单都会到财务那里,财务通过,并作出支出
(2)审核报销单业务涉及到哪些表?
报销单表,审核表,支出表
8.报销管理-审核报销单-控制层代码和业务层思路
(1)如何在后台sql中进行条件的拼接?
对于字符串的拼接,我们可以使用stringbuilder类型
//创建SQL命令
StringBuilder sql=new StringBuilder("select item.itemid,item.type,item.amount,item.itemdesc,"
+ " pm.paytime,exp.expid,emp.realname,emp2.realname"
+ " from payment pm join expense exp on pm.expid=exp.expid"
+ " join expenseitem item on exp.expid=item.expid join employee emp "
+ " on pm.payempid=emp.empid join employee emp2 on exp.empid=emp2.empid "
+ " where 1=1 ");
if (startDate!=null) {
sql.append("and paytime>=to_date('"+startDate+"','yyyy-MM-dd')");
}
if (endDate!=null) {
sql.append("and paytime>=to_date('"+endDate+"','yyyy-MM-dd')");
}
if (payEmpid!=null) {
sql.append("and pm.payEmpid='"+payEmpid+"'");
}
if (type!=0) {
sql.append("and item.type="+type);
}
9.报销管理-审核报销单-DAO层和业务层代码实现1
(1)在填充业务层代码过程中,需要注意哪些事项?
因为操作多个操作,涉及多个事务,所以我们需要将Dao层事务上升到业务层,要让都成功或者都失败
10.报销管理-审核报销单-DAO层和业务层代码实现2
(1)完成审核报销单业务层代码。
public void auditService(Auditing auditing) {
//开启事务
Connection conn = DBUtil2.getConnection();
try {
conn.setAutoCommit(false);//事务不再自动结束(提交,回滚),事务并没有在此开始
Expense exp = new Expense();
exp.setExpId(auditing.getExpId());
exp.setLastResult(auditing.getResult());
String result = auditing.getResult();
//审核通过吗
if("通过".equals(result)){//审核通过
//是财务吗
if(auditing.getAuditor().getPosition().getPosId()==6){//是财务
//添加支出记录
String payEmpId=auditing.getAuditor().getEmpId();
Date payTime=new Date();
int expId=auditing.getExpId();
Expense exp2=expDao.findByexpId(expId);
Double amount=(double) exp2.getTotalAmount();
String empId=exp2.getEmpId();
Payment payment=new Payment(payEmpId, amount, payTime, expId, empId);
pm.save(payment);
//修改报销单状态
exp.setStatus(Constants.EXPENSE_STATUS_PAIED);
exp.setNextAuditorId(null);
}else{
//金额大于2500吗 auditing.getExp().getTotalAmount()>2500 空指针异常
//获取报销单的金额
int expId = auditing.getExpId();
Expense exp2 = expDao.findByexpId(expId);
if(exp2.getTotalAmount()>2500){//大于2500
//当前审核人是总裁吗
if(Constants.CEOID.equals(auditing.getAuditor().getEmpId())){
//添加审核记录
auditDao.save(auditing);
//修改报销单状态
exp.setStatus(Constants.EXPENSE_STATUS_AUDITED);
exp.setNextAuditorId(Constants.CTOID); //财务
}else{
//添加审核记录
auditDao.save(auditing);
//修改报销单状态
exp.setStatus(Constants.EXPENSE_STATUS_AUDITING);
exp.setNextAuditorId(Constants.CEOID); //总裁
//exp.setNextAuditorId(auditing.getAuditor().getMgr().getEmpId());
}
}else{//小于等于2500
//添加审核记录
auditDao.save(auditing);
//修改报销单状态 下个处理人:财务 状态:审核通过
exp.setStatus(Constants.EXPENSE_STATUS_AUDITED);
exp.setNextAuditorId(Constants.CTOID); //财务
}
}
}else{//不通过,拒绝或者打回
//添加审核记录
auditDao.save(auditing);
//修改报销单状态
if("打回".equals(auditing.getResult())){
exp.setStatus(Constants.EXPENSE_STATUS_REJECT);
}else{
exp.setStatus(Constants.EXPENSE_STATUS_BACK);
}
exp.setNextAuditorId(null); //拒绝 打回 没有下个审核人
}
expDao.update(exp);
//结束事务(提交或回滚)
conn.commit();
} catch (Exception e) {//!!! 所有异常,保存运行时异常,SQLSyntaxErrorException
e.printStackTrace();
try {
conn.rollback(); //回滚数据
} catch (SQLException e1) {
e1.printStackTrace();
throw new MyException(e1.toString());
}
throw new MyException(e.toString());//向上一层抛出异常信息
}finally{
DBUtil2.closeAll(null, null, conn);
}
11.报销管理-理解数据库表和创建实体类
(1)简述系统中表之间的关系:
表之间用外键关联,在java中我们用的类与类之间的关系
12.报销管理-审核报销单-代码完善和业务流程图绘制
(1)在完成审核报销单功能后,你的感悟是什么?
对于mvc模式来说,一开始觉得代码量最多的在Dao层,然而现在才知道对于一个项目而言,最重要的是业务层,业务层才是逻辑和代码量最多的,而且业务层比较复杂
(2)在程序出错后或跟你预先结果不一致的时候,你的应对策略是什么?
第一步:查看出错的原因,根据输出的错误信息找到主要出错位置,然后如果是曾经遇到的错误,当然是自己解决,如果第一次遇到,而且还无从下手的话,先去百度上查看一下,然后看看别人的建议,自己在慢慢找错
13.收支管理-Echarts入门
(1)Echarts插件的作用?
是一款可视化类型的插件,具有丰富的可视化类型,多种数据格式无需转换直接使用,千万数据的前端展示,移动端可视化,多渲染方案,跨平台使用,深度的交互式数据搜索的特征
(2)如何使用Echarts插件?
第一步:引入echarts的js文件
第二步:准备一个div,并初始化echarts实例
第三步:展示数据
14.收支管理-使用Echarts柱状图显示收入统计信息-视图层和控制层
(1)使用Echarts柱状图显示收入统计信息的逻辑概述?
主要是返回类型的要求,我们需要在业务层进行数据的拼接,返回我们需要的json字符串类型,难点就是字符串的拼接