汽修系统
1.项目简介
本系统采用多模块开发思想,提供汽车的维修服务,维修配件的入库,维修配件的检索,车辆维修工单,维修明细单,结算单的管理,并提供维修之后的还车业务,还提供公共的维修结算工单查询,以及基础数据管理,报表的查询,以及权限管理等模块功能
2.技术支持
本系统采用MySQL数据库,使用Java EE进行开发,采取SSM平台的B/S架构,。程序使用MVC模式,多模块开发模式,采用三层架构,保证系统的可维护性和可扩展性。
3.项目大体模块
维修单管理模块
结算工单管理模块
登录管理模块
还车管理模块
汽车配件管理模块
系统管理模块
整体项目使用框架ssm(springmvc+spring+mabtis)
整个项目框架:
准备工作:配置文件如service中的applicationContext.xml文件需要引入mapper(controller层同理)
工具的类的抽取
BaseMapper
public interface BaseMapper <T>{
int deleteByPrimaryKey(Long id);
int insert(T record);
T selectByPrimaryKey(Long id);
List<T> selectForList(BaseQueryObject qo);
int updateByPrimaryKey(T record);
}
BaseQuery
public class BaseQuery {
//当前页
private int page = 1;
//每页显示条数
private int rows = 10;
//高级查询传入参数
private String keyword;
public String getKeyword() {
if(keyword.length()!=0){
return keyword.trim();
}
return null;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
//从哪一页开始显示数据
public int getStart(){
return (this.page-1)*rows;
}
}
分页PageResult
public class PageResult<T> {
private long total = 0;
private List rows = new ArrayList();
public PageResult() {
}
public PageResult(long total, List rows) {
this.total = total;
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List getRows() {
return rows;
}
public void setRows(List rows) {
this.rows = rows;
}
@Override
public String toString() {
return "PageResult{" +
"total=" + total +
", rows=" + rows +
'}';
}
}
生成相应的mapper/domain/service/controller/js/jsp文件(完成基本的CRUD)
velocity模板生成技术
public class VelocityMain {
//模板文件数组定义:顺序是你自己的
static String[] templateName = {
"domain.js", "domain.jsp", "DomainController.java"
, "DomainQuery.java", "DomainServiceImpl.java", "IDomainService.java"
};
// static String[] templateName = {
// "domain.js", "domain.jsp"
// };
//项目路径:
static final String jsFilePath = "D:/ideal-project/cars/cars-web/src/main/webapp/static/js/model/";
static final String jspFilePath = "D:/ideal-project/cars/cars-web/src/main/webapp/WEB-INF/views/";
static final String controllerFilePath = "D:/ideal-project/cars/cars-web/src/main/java/cn/itsources/web/controller/";
static final String queryFilePath = "D:/ideal-project/cars/cars-common/src/main/java/cn/itsources/query/";
static final String serviceImplFilePath = "D:/ideal-project/cars/cars-service/src/main/java/cn/itsources/service/impl/";
static final String serviceFilePath = "D:/ideal-project/cars/cars-service/src/main/java/cn/itsources/service/";
//生成文件的路径数据定义:这个要和templateName对应起来
static String[] outFileRootPath = {
jsFilePath, jspFilePath, controllerFilePath, queryFilePath
, serviceImplFilePath,serviceFilePath
};
//
// static String[] outFileRootPath = {
// jsFilePath, jspFilePath
// };
//可能有多个domain需要生成
static String[] domain = {"Setted"};
/**
* 1:定义模板
* 2:使用Velocity生成模板:
* 2.1:初始化Velocity:设置加载方式:classpath下加载
* 2.2:设置Velocity的上下文
* 2.3:从classpath下读取模板,输出到文件
*
* @param args
*/
public static void main(String[] args) throws ClassNotFoundException {
for (String domainMame : domain) {
// domainName = Employee
Properties p = new Properties();
// 2.1:初始化Velocity:设置加载方式:classpath下加载
// 使用classpath加载:org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
p.setProperty(Velocity.RESOURCE_LOADER, "class");
p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(p);
//2.2:设置Velocity的上下文
VelocityContext context = new VelocityContext();
// domainName = Employee
// domainLower= employee
String domainLower = domainMame.substring(0, 1).toLowerCase() + domainMame.substring(1);
//使用Department代替模板文件中:Domain
context.put("Domain", domainMame); //Department
context.put("domain", domainLower); //department
//
context.put("fieldList",scanDomain(domainMame));
//遍历模板,每一个模板都生成一个文件
for (int i=0;i<templateName.length;i++) {
//2.3:读取模板,输出到文件
//从classpath下读取模板
String tempName = templateName[i];
// i=0==>tempName=domain.js
String templateFile = "template/" + tempName;
// templateFile=template\domain.js
//根据模板的索引读取对应生成文件的路径:
String outFilePath = outFileRootPath[i];
// outFilePath=F:\java0830\itsource-parent\crm-web\src\main\webapp\static\js\
//"F:/java0830/itsource-parent/crm-web/src/main/webapp/WEB-INF/views/";
boolean views= outFilePath.contains("views")||outFilePath.contains("js");
if(views){
// F:/java0830/itsource-parent/crm-web/src/main/webapp/WEB-INF/views/employee/
outFilePath=outFilePath+"/"+domainLower+"/";
}
// outFile=outFilePath+domain.js==>outFilePath+employee.js
String outFile = outFilePath + tempName;
outFile=outFile.replaceAll("Domain",domainMame).replaceAll("domain",domainLower);
try {
File file = new File(outFile);
File parentFile = file.getParentFile();
//文件不存在,就创建
if (!parentFile.exists()) {
parentFile.mkdirs();
}
//文件输出
FileWriter fileWriter = new FileWriter(file);
Template template = Velocity.getTemplate(templateFile, "utf-8");
template.merge(context, fileWriter);
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* List<FieldVo> voList = scanDomain("Employee");
for (FieldVo fieldVo : voList) {
System.out.println(fieldVo);
}*/
}
private static List<FieldVo> scanDomain(String domainMame) throws ClassNotFoundException {
List<FieldVo> voList=new ArrayList<>();
// domainMame=Employee
// cn.itsource.crm.domain.Employee
String clazzPath="cn.itsources.domain."+domainMame;
Class<?> c = Class.forName(clazzPath);
System.out.println(c);
//获取字段
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
//判断这个字段上是否有EasyuiColumn
if(declaredField.isAnnotationPresent(EasyuiColumn.class)){
EasyuiColumn easyuiColumn = declaredField.getAnnotation(EasyuiColumn.class);
//获取到注解的title的值
String title = easyuiColumn.title();
String name = declaredField.getName();
FieldVo fieldVo=new FieldVo();
fieldVo.setField(name);
fieldVo.setTitle(title);
voList.add(fieldVo);
}
}
for (FieldVo fieldVo : voList) {
System.out.println(fieldVo);
}
return voList;
}
}
FieldVo 结合VelocityMain 完成jsp
public class FieldVo {
//domain的field
private String title;
//domain的title:标签上的值
private String field;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
4.负责模块 结算工单管理模块
当维修人员维修车辆完成之后,交互给结算人员,由结算人员填写结算单据,通知客户进行付款操作;
结算单结算管理(Setted)
业务概述
车辆维修完毕之后,由结算人员填写结算单据,进行车辆的结算。结算之后,更新维修工单状态;
前台jsp代码展示:
<div id="settedDialog" class="easyui-dialog" title="数据操作" data-options="closed:true,modal:true"
style="width:400px;padding:10px">
<form id="settedForm" method="post">
<input id="settedId" type="hidden" name="id">
<table cellpadding="5">
<tr>
<td>客户名称:</td>
<td><input class="easyui-validatebox" type="text" name="custormer"
data-options="required:true,validType:'custormer'"></input></td>
</tr>
<tr>
<td>应付金额:</td>
<td><input id="reAmount" class="easyui-validatebox" type="text" name="reAmount"
data-options="required:true"></input></td>
</tr>
<tr>
<td>实付金额:</td>
<td><input class="easyui-validatebox" type="text" name="payAmount"
validType="equalTo['#reAmount']" invalidMessage="与应付金额不同"
data-options="required:true"></input></td>
</tr>
<tr>
<td>支付方式:</td>
<td>
<%--//下拉选择支付方式--%>
<select style="width: 120px" data-options=" panelHeight:'auto'" name="payId" class="easyui-combobox">
<option name="1" value="1">现金支付</option>
<option name="2" value="2">银行卡支付</option>
<option name="3" value="3">信用卡支付</option>
<option name="4" value="4">微信支付</option>
<option name="5" value="5">支付宝支付</option>
<%--</select><a href="javascript:void(0)" class="easyui-linkbutton c6" data-cmd="settedSave">支付</a>--%>
</td>
</tr>
</table>
<div style="text-align:center;padding:5px">
<a href="javascript:void(0)" class="easyui-linkbutton c1" data-cmd="settedSave">支付</a>
<a href="javascript:void(0)" class="easyui-linkbutton c2" onclick="$('#settedDialog').dialog('close')">取消</a>
</div>
</form>
</div>
<%--验证金额是否形同--%>
<script type="text/javascript">
$.extend($.fn.validatebox.defaults.rules, {
/*必须和某个字段相等*/
equalTo: {
validator: function (value, param) {
return $(param[0]).val() == value;
}, message: '字段不匹配'
}
});
</script>
js代码js— //变量的抽取:省略
'setted': function () {
//获取选中当前行的数据
var row = repairorderDatagrid.datagrid("getSelected");
//判断是否选中行
if (!row) {
$.messager.alert('提示', '请选择', 'info');
} else {
//打开结算面板
settedDialog.dialog("open").dialog('center').dialog('setTitle', '结算维修单');
//通过ajax请求通过客户姓名后台查询出相应的数据
$.ajax({
url: "/setted/findSetted",
type: "post",
data: {
"custormer": row.custormer
},
//返回数据类型转为json
dataType: "json",
//成功接收后台数据
success: function (data) {
//将数据加载到表单中
console.debug(data)
settedForm.form("load", data);
}
});
}
},
//支付并把结算清单保存
'settedSave': function () {
$.messager.confirm('交易平台', '确认付款', function (r) {
//支付操作
settedForm.form('submit', {
url: "/setted/saveOrUpdate",
success: function (data) {
var result = JSON.parse(data);
if (result.success) {
repairorderDatagrid.datagrid('reload');
settedDialog.dialog("close");
// 跳转页面/setted/index
//刷新
window.location.href="/setted/index";
} else {
$.messager.alert("提交失败", result.msg, 'error')
}
}
})
});
},
结算单的金额验证---- 支付方式选择---- 提交前再次确认
界面展示
取消结算单(Setted)
jsp
<table id="settedDatagrid"></table>
js— //变量的抽取:省略
'deleteState':function () {
//先获取数据
var row = settedDatagrid.datagrid('getSelected');
//做一个判断:是否选中
if (row){
if(row.settlementStatus==0){
$.messager.alert('操作提示',"已经是未结算状态!",'error');
}
else if(row.settlementStatus==1) {
$.messager.confirm('温馨提示','请仔细核对:[<font color="pink">'+row.custormer+"</font>]未结算?",function(r){
// 选中:确认的操作:调用后台的删除方法:发送ajax调用
if (r){
// 发送ajax调用 $.get(url,params,function(d){},type)
$.get('/setted/deleteState?sId='+row.sId,function (d) {
if(d.success){
//true:成功
$.messager.alert('操作提示',d.msg,'info');
//页面刷新
cmdObj.refresh();
}else{
//false:失败:提示
$.messager.alert('错误提示',d.msg,'error');
}
},'json')
}
})
};
}else{
$.messager.alert('温馨提示','请选中!!!','warning');
}
},
业务概述
如果结算有问题,可以取消结算单
界面概要
setted.所有方法的mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itsources.mapper.SettedMapper">
<resultMap id="BaseResultMap" type="cn.itsources.domain.Setted">
<id column="s_id" jdbcType="BIGINT" property="sId" />
<result column="custormer" jdbcType="VARCHAR" property="custormer" />
<result column="main_id" jdbcType="VARCHAR" property="mainId" />
<result column="setted_time" jdbcType="TIMESTAMP" property="settedTime" />
<result column="re_amount" jdbcType="DECIMAL" property="reAmount" />
<result column="pay_amount" jdbcType="DECIMAL" property="payAmount" />
<result column="pay_id" jdbcType="INTEGER" property="payId" />
<result column="settlement_status" jdbcType="INTEGER" property="settlementStatus" />
<result column="send_status" jdbcType="INTEGER" property="sendStatus" />
</resultMap>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from setted
where s_id = #{sId,jdbcType=BIGINT}
</delete>
<!--更新结算状态-->
<update id="deleteState" parameterType="cn.itsources.domain.Setted">
UPDATE setted set settlement_status =0
where s_id = #{sId,jdbcType=BIGINT}
</update>
<!--更新还车状态-->
<update id="sendState" parameterType="cn.itsources.domain.Setted">
UPDATE setted set send_status = 1
where main_id = #{mainId,jdbcType=BIGINT}
</update>
<insert id="insert" parameterType="cn.itsources.domain.Setted">
insert into setted (s_id, custormer, main_id,
setted_time, re_amount, pay_amount,
pay_id, settlement_status, send_status
)
values (#{sId,jdbcType=BIGINT}, #{custormer,jdbcType=VARCHAR}, #{mainId,jdbcType=VARCHAR},
#{settedTime,jdbcType=TIMESTAMP}, #{reAmount,jdbcType=DECIMAL}, #{payAmount,jdbcType=DECIMAL},
#{payId,jdbcType=INTEGER}, #{settlementStatus,jdbcType=INTEGER}, #{sendStatus,jdbcType=INTEGER}
)
</insert>
<update id="updateByPrimaryKey" parameterType="cn.itsources.domain.Setted">
update setted
set send_status = #{sendStatus,jdbcType=INTEGER}
where custormer = #{custormer,jdbcType=BIGINT}
</update>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select s_id, custormer, main_id, setted_time, re_amount, pay_amount, pay_id, settlement_status,
send_status
from setted
where s_id = #{sId,jdbcType=BIGINT}
</select>
<!--分页查询-->
<!---->
<sql id="base_where">
<where>
<if test="keyword != null">
and ( custormer like concat("%",#{keyword},"%") or settlement_status like concat("%",#{keyword},"%") )
</if>
</where>
</sql>
<select id="selectForList" resultMap="BaseResultMap">
select s_id, custormer, main_id, setted_time, re_amount, pay_amount, pay_id, settlement_status,
send_status
from setted
<include refid="base_where" />
</select>
<!--嵌套结果-->
<select id="findMainId" parameterType="string" resultType="long">
SELECT red.main_id
FROM repairorder r
LEFT JOIN repairorderitem red ON r.id = red.main_id
WHERE r.custormer = #{custormer}
GROUP BY r.id
</select>
<select id="findSetted" parameterType="string" resultType="cn.itsources.util.SettedVo">
SELECT re.id,re.custormer,SUM(red.totalamt) as reAmount,SUM(red.totalamt) as payAmount
FROM repairorder re
LEFT JOIN repairorderitem red ON re.id = red.main_id
where re.custormer = #{custormer}
</select>
<!--订单号查询索引-->
<select id="selectAll" resultType="cn.itsources.util.SettedVo" >
select s.custormer, s.pay_amount, rc.address , s.setted_time
from setted s
left join returncar rc on s.main_id = rc.main_id
<where>
<if test="keyword!=null">
and s.main_id = #{keyword}
</if>
</where>
GROUP BY s.main_id
</select>
</mapper>
心得:代码不是问题 思路才是重要的,用velocity代码生成器,多用时间走业务逻辑,CRUD是个java程序员都会。所以要注重思路。过程各种bug都是正常的,静下心都能发现问题。本项目问题最多的是刚接触的全文搜索引擎lucene,尤其是搜索索引。
本文也结合lucene做出了简单的更新查询功能采用了IKAnalyzer分词器。
团队开发刚使用svn各种冲突,用多了都是没有问题的