-一、需求分析

-二、概要设计

-三、详细设计

    1.添加车辆

    2.实现租车业务

    3.实现还车业务

    数据层代码


-一、需求分析与数表设计

需求图:

wKiom1nEyPCiv6hyAAJH0lmmZA0317.png


发现类:

    01.moto类(汽车父类):

        01.1:bus类(客车类)

        01.2:car类(轿车类)

        01.3:truck类(卡车类)

    02.mototype类(汽车类型类)

    03.用户类:软件系统的使用者,登录该系统 管理的 人,比如:管理员、业务经理等。

    04.客户类:租车的人。

    05.公司类:用于处理租车换车业务流程的人。

-二、概要设计

数据库设计:

wKiom1nEzmKQO6VEAAI0x96Nd14181.png


-三、详细设计

  1. 实现各车的信息录入

wKioL1nE01ex5_gkAAB_b7VOqWo940.png

    一个问题:卡车跟大巴和轿车录入是不一样的,所以在业务层需要判断是什么车型,但这样代码比较臃肿,不利于扩展,不是面向对象编程。

    解决:采用面向对象的特点(继承和多态),在moto类建立录入车信息的方法,这样轿车客车大巴继承moto类就可以有自己的录入车信息的方法。


代码演示:

moto类:

public abstract class Moto {
	private String mno;              //车牌号
	private int seatCount;       
	private MotoType mtype;		  	
	

	//这里省略get\set方法
	
	public Moto(MotoType mtype,String mno,int seatCount){
		this.mno = mno;
		this.seatCount = seatCount;
		this.mtype = mtype;
	}
	
	/**
	 * 把当前对象存储到数据库中
	 * @throws Exception
	 */
	public void saveDB() throws Exception{
		CompanyDao dao = new CompanyDao();
		try {
			dao.addMoto(this);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			dao.closeConnection();
		}
	}
}

car类:可以直接使用moto类中的方法

public class Car extends Moto{
	public Car(MotoType mtype,String mno) {
		super(mtype,mno, 5);
	}
}

truck类:重写了moto类的saveDB()方法

public class Truck extends Moto{
	private int dun;
	private double priceEachDun;            //每吨每天的单价	

	public int getDun() {
		return dun;
	}
	public double getPriceEachDun() {
		return priceEachDun;
	}
	public void setPriceEachDun(double priceEachDun) {
		this.priceEachDun = priceEachDun;		
	}
	public Truck(MotoType mtype, String mno, int seatCount,int dun) {
		super(mtype, mno, seatCount);
		this.dun = dun;		
	}
	public double getDayMoney() {
		return priceEachDun*dun;
	}
	
	/**
	 * 把当前对象存储到数据库中  ----------重写
	 * @throws Exception
	 */
	@Override
	public void saveDB() throws Exception{
		CompanyDao dao = new CompanyDao();
		try {
			dao.beginTransaction();
			dao.addMoto(this);
			TruckEntity truckEntity = new TruckEntity();
			truckEntity.setMno(this.getMno());
			truckEntity.setDun(dun);
			truckEntity.setPriceEachDun(priceEachDun);
			dao.addTruck(truckEntity);
			dao.commit();
		} catch (Exception e) {
			e.printStackTrace();
			dao.rollback();
			throw e;
		}finally{
			dao.closeConnection();
		}
	}
}

在业务逻辑层方法就很简单了:

private List<Moto> motos;
/**
* 添加汽车
* @param moto
* @throws Exception
*/
public void addMoto(Moto moto) throws Exception{
	if(moto != null ){			
		moto.saveDB();                      //OO多态
		motos.add(moto);
	}else{
		throw new Exception("入参moto错误");
	}		
}


2.实现租车业务

图解:

wKioL1nE1NrReZ66AAFU_AKkhqM429.png

    注意:由于整个租车过程包含多个表的修改,比如加入两个订单在差不多时间操作同一辆车,肯定会有一个订单有问题,这是就需要保证事务的一致性和完整性。


在业务逻辑层的代码就可以:

public class RentCompany {
	
	private String name;	
	private List<Moto> motos;               //待租赁的汽车
	
	public String getName() {
		return name;
	}	

	public List<Moto> getMotos() {
		return motos;
	}

	public RentCompany(String name){
		
		this.name = name;
		motos = new ArrayList<Moto>(50);
		
	}	
	
	/**
	 * 汽车租赁
	 * @param motos
	 * @param client
	 * @param rentinfo
	 * @return            租赁成功,返回订单号
	 * @throws Exception
	 */
	public String rent(List<Moto> motos,TClient client,TRentInfo rentinfo) throws Exception{
		String rentno = null;
		
		if(motos != null && client != null && rentinfo!= null){
			CompanyDao dao = new CompanyDao();
			try {
				dao.beginTransaction();                                 //开启事务
				//添加客户数据		
				dao.addTClient(client);
				//添加汽车租赁信息
				rentno = dao.addRentInfo(rentinfo);
				//添加租赁明细
				for(Moto moto : motos){
					TRentDetail rentDetail = getTRentDetail(rentno,moto);
	                dao.addRentDetail(rentDetail);
				}			
				dao.commit();                                         //提交事务	
			} catch (Exception e) {
				dao.rollback();                                       //回滚事务
				rentno = null;
				throw e;
			}finally{
				dao.closeConnection();
			}		
		}else{			
			throw new Exception("入参错误,请检查");
		}		
		
		return rentno;
	}
	
	private TRentDetail getTRentDetail(String rentno,Moto moto){
		TRentDetail detail = new TRentDetail();
		
		detail.setMno(moto.getMno());
		detail.setRentno(rentno);
		detail.setDaymoney(moto.getDayMoney());
		
		return detail;
	}	
}

3.实现还车业务

业务流程:计算租金总额、添加还车信息、给订单写入租金总额、设置车辆信息

/**
* 还车,计算租赁的总价
* @param moto
* @return
*/
public double rentBack(String rentno) throws Exception{
	double allMoney = 0;

	if(rentno != null){
		CompanyDao dao = new CompanyDao();
		try {
		        dao.beginTransaction();
			//计算租金总额
			allMoney = dao.countAllPayMoney(rentno);
			//添加还车信息
			dao.addRentBackInfo(rentno);
			//给订单写入租金总额
			dao.writeAllPayMoney(rentno, allMoney);
			//设置车辆的状态
			dao.setRentBackMotoState(rentno);
			dao.commit();				
		} catch (Exception e) {
			dao.rollback();
			throw e;
		}finally{
			dao.closeConnection();
		}			
	}else{
		throw new Exception("入参错误");
	}

	return allMoney;		
}


对应dao层代码:

basedao

public class BaseDao {
	protected Connection conn;		
	public Connection getConn() {
		return conn;
	}

	public void setConn(Connection conn) {
		this.conn = conn;
	}	

	public void openConnection() throws ClassNotFoundException,SQLException{
		
		    //通过反射技术,对oracel的驱动对象进行类的加载 (其实是在做类型检查)
			//在类的加载时,会调用OracleDriver中的静态代码块和静态变量初始化
		if(this.conn == null || this.conn.isClosed()){
			Class.forName("oracle.jdbc.driver.OracleDriver");  
			conn = DriverManager.getConnection("jdbc:oracle:thin:@10.0.19.252:1521:orcl","testdb","1111");
		}	
		
	}
	
	public void beginTransaction() throws Exception{
		this.openConnection();
		if(this.conn != null){			
			this.conn.setAutoCommit(false);			             //手动提交模式
		}		
	}
	
	public void commit() throws Exception{
		if(this.conn != null){
			this.conn.commit();
		}
	}
	
	public void rollback() throws Exception{
		if(this.conn != null){
			this.conn.rollback();
		}
	}
	
	public void closeConnection() {
		if(this.conn != null){
			try {
				this.conn.close();	
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}
public class CompanyDao extends BaseDao{
	/**
	 * 根据订单号,计算需要的租金总额
	 * @param rentno
	 * @return
	 * @throws Exception
	 */
	public double countAllPayMoney(String rentno) throws Exception{
		
		double allMoney = 0;
		double dayMoneys = 0;

		String sql = " select  sum(daymoney) dayMoneys from trentinfo r,trentdetail d where r.rentno = d.rentno"
				    + " and r.rentno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1,rentno);
		ResultSet rs = ps.executeQuery();
		while(rs.next()){
			dayMoneys = rs.getDouble("dayMoneys");
		}
		RentinfoDto rentinfo = getRentInfo(rentno);
		int days = (int)((new Date()).getTime() - rentinfo.getRentBeginDate().getTime())/(24*3600*1000) + 1;
		 
		allMoney = dayMoneys*days;
		
		return allMoney;
		
	}
	
	/**
	 * 根据订单编号,返回订单信息
	 * @param rentno
	 * @return
	 */
	public RentinfoDto getRentInfo(String rentno) throws Exception{
		RentinfoDto rentinfo = null;
		
		String sql = " select r.rentno,r.clno,r.eno,r.operator,r.rentbengindate,r.diyamoney,r.payallmoney, b.backdate  " +
				" from trentinfo r left join  trentback b on  r.rentno = b.rentno and r.rentno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1,rentno);
		ResultSet rs = ps.executeQuery();
		while(rs.next()){
			rentinfo = new RentinfoDto();
			rentinfo.setBackDate(rs.getDate("backdate"));
			rentinfo.setClno(rs.getString("clno"));
			rentinfo.setDiyaMoney(rs.getDouble("diyamoney"));
			rentinfo.setEno(rs.getString("eno"));
			rentinfo.setOperator(rs.getString("operator"));
			rentinfo.setPayAllMoney(rs.getDouble("payallmoney"));
			rentinfo.setRentBeginDate(rs.getDate("rentbengindate"));
			rentinfo.setRentno(rs.getString("rentno"));
		}
		
		return rentinfo;
		
	}
	
	/**
	 * 还车时,给订单写入租金总额
	 * @param rentno
	 * @param allMoney
	 * @throws Exception
	 */
	public void writeAllPayMoney(String rentno,double allMoney) throws Exception{
		String sql = "update trentinfo set payallmoney=? where rentno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setDouble(1, allMoney);
		ps.setString(2, rentno);
		ps.executeUpdate();
		ps.close();
	}
	
	/**
	 * 添加还车信息
	 * @param rentno
	 * @throws Exception
	 */
	public void addRentBackInfo(String rentno) throws Exception{
		String sql = "insert into trentback values(?,?)";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, rentno);
		ps.setTimestamp(2,new java.sql.Timestamp(new Date().getTime()));
		ps.executeUpdate();
		ps.close();
	}
	
	/**
	 * 还车时,设置所有订单中的车辆状态为'01'
	 * @param rentno
	 * @throws Exception
	 */
	public void setRentBackMotoState(String rentno) throws Exception{
		
		String sql = "select d.mno  from trentinfo r,trentdetail d where r.rentno = d.rentno and r.rentno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1,rentno);
		ResultSet rs = ps.executeQuery();
		while(rs.next()){
			String mno = rs.getString("mno");
			updateRentBackMotoState(mno);
		}
		rs.close();
		ps.close();		 
	}
	
	public void updateRentBackMotoState(String mno) throws Exception{
		String sql = "update tmoto set state='01' where mno=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, mno);
		ps.executeUpdate();		   
		ps.close();
	}
	
	/**
	 * 添加客户数据
	 * @param client
	 * @throws Exception
	 */
	public void addTClient(TClient client) throws Exception{
		//查询客户是否存在
		boolean bRet = isHaveClient(client.getTel());
		if(!bRet){
			//添加客户数据	
			String sql = "insert into tclient values(?,?,?,?,?)";
			this.openConnection();
			PreparedStatement ps = this.conn.prepareStatement(sql);
			ps.setString(1, client.getTel());
			ps.setString(2, client.getCname());
			ps.setString(3, client.getCid());
			ps.setString(4, client.getTel());
			ps.setString(5, client.getAddress());
			ps.executeUpdate();
			ps.close();
		}		
	}
	
	/**
	 * 通过手机号,查询指定用户是否存在
	 * @param tel
	 * @return
	 */
	private boolean isHaveClient(String tel) throws Exception{
		boolean bRet = false;
		
		String sql = "select * from tclient where tel=?";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, tel);
		ResultSet rs = ps.executeQuery();
		while(rs.next()){
			bRet = true;
		}
		rs.close();
		ps.close();
		
		return bRet;
	}
	
	/**
	 * 汽车租赁
	 * @param rentinfo 
	 * @return     返回订单号
	 * @throws Exception
	 */
	public String addRentInfo(TRentInfo rentinfo) throws Exception{
		String sql = "insert into trentinfo values(?,?,?,?,?,?,?)";
		
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");
		String rentno = "rno-" + sd.format(new Date()) + "-" + (new Date()).getTime();
		ps.setString(1, rentno);
		ps.setString(2, rentinfo.getClno());
		ps.setString(3, rentinfo.getEno());
		ps.setString(4, rentinfo.getOperator());
        ps.setDate(5, new java.sql.Date(rentinfo.getRentBeginDate().getTime()));
		ps.setDouble(6, rentinfo.getDiyaMoney());
		ps.setDouble(7, rentinfo.getPayAllMoney());
		ps.executeUpdate();
		ps.close();
		
		return rentno;
	}
	
	/**
	 * 添加租赁明细
	 * @param rentDetail
	 * @throws Exception
	 */
	public void addRentDetail(TRentDetail rentDetail) throws Exception{
		//添加明细
		String sql = "insert into TRentDetail values(seq_rentdetail_id.nextval,?,?,?)";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, rentDetail.getRentno());
		ps.setString(2, rentDetail.getMno());
		ps.setDouble(3,rentDetail.getDaymoney());
		ps.executeUpdate();
		ps.close();		
		//修改汽车状态值
		updateMotoStateByRent(rentDetail.getMno());
	}
	
	/**
	 * 修改汽车状态值,从未出租改为出租中
	 * @param moto
	 * @throws Exception
	 */
	private void updateMotoStateByRent(String mno) throws Exception{
	   String sql = "update tmoto set state='02' where mno=? and state='01'";
	   this.openConnection();
	   PreparedStatement ps = this.conn.prepareStatement(sql);
	   ps.setString(1, mno);
	   int iRet = ps.executeUpdate();
	   if(iRet==0){
		   throw new MotoRentFailException( mno+ ",该车已被别人租用,请重新选择");
	   }
	   ps.close();
	}
	
	/**
	 * 添加汽车单表数据
	 * @param moto
	 * @throws Exception
	 */
	public void addMoto(Moto moto) throws Exception{
		String sql = "insert into tmoto values(?,?,?,?)";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1,moto.getMno());
		ps.setString(2,moto.getMtype().getTno());
		ps.setInt(3, moto.getSeatCount());
		ps.setString(4, MotoState.PREPARED_RENT);
		ps.executeUpdate();
		ps.close();
	}
	
	/**
	 * 添加卡车单表数据
	 * @param truck
	 * @throws Exception
	 */
	public void addTruck(TruckEntity truck) throws Exception{
		String sql = "insert into truck values(?,?,?)";
		this.openConnection();
		PreparedStatement ps = this.conn.prepareStatement(sql);
		ps.setString(1, truck.getMno());
		ps.setInt(2, truck.getDun());
		ps.setDouble(3, truck.getPriceEachDun());
		ps.executeUpdate();
		ps.close();		
	}


}