基于SSM框架的狼途汽车门店管理系统的设计与实现
✌全网粉丝20W+,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌
🍅文末获取项目下载方式🍅
一、项目背景介绍:
汽车美容这个概念进入中国都已经有十多年之久了,汽车的美容方式也逐渐发展的多式多样。众多4S店在中国的立足也说明着汽车美容行业其实已经正式的走向了成熟的发展时期。不得不说,中国的汽车市场是非常庞大的,得益于中国的经济发展速度太迅猛了,人们的生活水平日益提升,很多大城市已经能做到汽车是家庭的必备品,甚至于很多家庭都不止一台汽车。汽车多了,那么汽车门店也像春后的竹笋一般出现在我国的各地。
汽车的服务行业算是一个比较不错的“产业”。主要是因为这个行业是属于社会经济高速发展的产物,是根据汽车保有量的增加而随之形成的新型行业。那么大火的汽车的后服务市场究竟是什么呢?汽车的后服务市场可以这样理解,你买完车之后,你如果想让车的内饰变得更加美观,这时候门店就能帮你解决这个问题。从宏观的角度上来说,其实就是有关于购车后的所有服务门店都可以帮你解决你的需求。但是由于我国的汽车后服务市场其实才算是刚刚起步,属于极度不稳定的状态。今后这几年之间是肯定会进行一场激烈的竞争,经过重新洗牌之后的结局才是真正汽车服务业的开始。届时,能通过这些竞争“存活”下来的门店必定是那些懂得用信息化管理技术去运营的。因为只有这些会抓住机会的店家才能运筹帷幄。
虽说这几年中国互联网技术发展的还算比较不错,但是较于西方那些发达国家,其实还是有一点差距的。原因在于欧美那些国家主要推崇的都是O2O模式,该模式其实就是利用起互联网在现今社会的优势,用真正的信息化去管理门店。让门店真正可以做到“无人管理”。中国在O2O模式的应用上还算是比较少的,中国汽车门店其实很多还是使用纯线下的方式在运营。这种运营方式其实不符合现在的发展境况,毕竟现在是属于信息化的时代。一个门店如果是纯线下的模式在面对庞大的信息量的时候,人工管理是没有什么办法管理的。面对这种情况,其实是可以借鉴一下那些欧美国家的做法,使用数据库去存取这些信息,发挥出互联网时代应该有的优势,用一个功能完善、轻量、能处理大量数据的汽车门店管理系统去管理门店,从而真正的实现机械化管理,让汽车门店的运营变得更加便利与先进。
二、项目技术简介:
- JAVA:Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
- Spring:Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
- Mybatis:MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。 - Bootstrap:Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成。Bootstrap一经推出后颇受欢迎,一直是GitHub上的热门开源项目,包括NASA的MSNBC(微软全国广播公司)的Breaking News都使用了该项目。 国内一些移动开发者较为熟悉的框架,如WeX5前端开源框架等,也是基于Bootstrap源码进行性能优化而来。
- Html:HTML的全称为超文本标记语言,是一种标记语言。它包括一系列标签.通过这些标签可以将网络上的文档格式统一,使分散的Internet资源连接为一个逻辑整体。HTML文本是由HTML命令组成的描述性文本,HTML命令可以说明文字,图形、动画、声音、表格、链接等。
超文本是一种组织信息的方式,它通过超级链接方法将文本中的文字、图表与其他信息媒体相关联。这些相互关联的信息媒体可能在同一文本中,也可能是其他文件,或是地理位置相距遥远的某台计算机上的文件。这种组织信息方式将分布在不同位置的信息资源用随机方式进行连接,为人们查找,检索信息提供方便。
三、系统功能模块介绍:
四、数据库设计:
1:管理员表
(admin)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
user_name | varchar(50) | NULL | 用户名 |
pass_word | varchar(255) | NULL | 密码 |
head_img | varchar(200) | NULL | 头像 |
nick_name | varchar(50) | NULL | 昵称 |
type | int(3) | NULL | 类型[1:员工 |
2:配件表
(parts)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
parts_name | varchar(50) | NULL | 配件名称 |
supplier_id | bigint(20) | NULL | 所属供应商 |
price | varchar(10) | NULL | 单价 |
stock | int(20) | NULL | 库存 |
cover_img | varchar(200) | NULL | 配件 |
content | text | NULL | 配件用途 |
type_id | bigint(20) | NULL | 所属分类 |
current_stock | int(20) | NULL | 当前库存 |
3:配件分类
(parts_type)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
parts_type_name | varchar(255) | NULL | 配件分类 |
4:服务项目表
(projects)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
subscribe_id | bigint(20) | NULL | 预约表ID |
user_id | bigint(20) | NULL | 用户ID |
content | text | NULL | 主要服务内容 |
type | int(3) | NULL | 项目类别[1:汽车美容 |
5:用户预约表
(subscribe)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
user_id | bigint(20) | NULL | 用户ID |
su_info | text | NULL | 预约内容 |
subscribe_time | datetime | NULL | 预约时间 |
status | int(3) | NULL | 预约状态[1:预约中 |
6:供应商表
(supplier)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
supplier_name | varchar(50) | NULL | 供应商名称 |
supplier_type | varchar(50) | NULL | 供应商类别 |
supplier_localtion | varchar(255) | NULL | 供应商所在地址 |
supplier_boss_name | varchar(50) | NULL | 供应商联系人名称 |
supplier_tel | varchar(20) | NULL | 联系电话 |
7:项目配件表
(user_parts)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
parts_id | bigint(20) | NULL | 配件ID |
use_num | int(20) | NULL | 使用数量 |
projects_id | bigint(20) | NULL | 维修项目ID |
8:用户表(users)
字段名 | 类型 | 默认值 | 列注释 |
---|---|---|---|
id | bigint(20) | NULL | 主键ID |
user_name | varchar(255) | NULL | 用户名 |
pass_word | varchar(255) | NULL | 密码 |
nick_name | varchar(50) | NULL | 昵称 |
sex | int(3) | NULL | 性别[1:男 |
五、功能模块:
-
前台页面的功能实现:当点击马上预约的时候,就会弹出预约信息的模态框,预约信息包括了姓名、电话、预约的门店(可以下拉选择)、预约的业务(下拉选择)、预约的时间、备注说明。点击确定预约以后会提示用户预约成功。点击ok之后就可以返回门店首页。
-
登录页面功能的实现:当输入账号不存在或者密码错误的时候,会提示账号或者密码错误。当输入的账号密码正确的时候,会跳转到员工信息页面,并在菜单栏显示当前登录的用户名
-
员工页面功能的实现:点击添加/编辑的时候,会跳转到编辑页面。当输入的信息不符合条件的时候将不允许被保存 。
点击导出员工表的时候,会直接生成一张包含所有员工信息的表格返回给用户。
点击导入按钮的时候,会有下载模板和选择文件,用户可以下载模板,然后再模板表格填写员工数据,再选择刚才编写的文件,点击保存之后就会跳转回员工信息页面。 -
权限页面功能的实现:因为系统的代码可能会改动,那么就需要在页面提供一个按钮,作用是为了权限表达式和数据库的权限表达式同步。点击重新加载按钮,会提示是否重新加载权限。点击确定之后会更新权限页面。
-
公告页面功能的实现:点击查看按钮的时候对应的已读状态会改成已读。而且会跳转至公告查看的页面。
点击发布按钮的时候状态会变成已发布,同时刷新公告页面。 -
门店信息页面功能的实现:点击编辑的时候进入到信息编辑页面,有个查看附件的按钮,点击该按钮的时候会打开门店的营业执照照片。可以选择文件作为营业执照的照片进行上传。
-
预约信息页面功能的实现:点击确认预约的时候,预约单的状态会变成履行中。点击取消预约的时候,预约单的状态会变成废弃。
六、代码示例:
前台页面的功能实现
/**
* 展示前端页面方法
* @param model
* @return
*/
@RequestMapping("/index")
public String index(Model model){
//获取所有的数据字典
List<SystemDictionary>systemDictionaries=systemDictionaryService.selectTitle("business");
model.addAttribute("systemDictionaries",systemDictionaries);
//获取总店对象
Business business = businessService.getBymainStore(true);
model.addAttribute("business",business);
//获取所有的门店信息
List<Business> businesses = businessService.listAll();
model.addAttribute("businesses",businesses);
return "index";
}
登录页面功能的实现
public class LoginController {
@Autowired
private IEmployeeService employeeService;
@RequestMapping("/empLogin")
@ResponseBody
public JsonResult empLogin(String username,String password){
try {
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
SecurityUtils.getSubject().login(token);
return new JsonResult();
} catch (UnknownAccountException e) {
return new JsonResult(false, "账号不存在");
} catch (IncorrectCredentialsException e) {
return new JsonResult(false, "密码错误");
} catch (Exception e) {
e.printStackTrace();
return new JsonResult(false, "登录异常,请联系管理员");
}
}
员工页面功能的实现
public class CheckLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod){
//拦截到的都是请求动态资源的请求
//判断是否有登录 有放行 没有跳转登录页面
Object emp = request.getSession().getAttribute(UserContext.USER_IN_SESSION);
if (emp == null){
response.sendRedirect("/login.html");
return false;
}
}
return true;
}
}
权限页面功能的实现
public void reload() {
//1.一次性的把数据库所有的权限信息查出来.
List<Permission> permissions = permissionMapper.selectAll();
//2.创建一个set集合 用来存储权限表达式
Set<String> expressionSet = new HashSet<>();
for(Permission p:permissions){
//3.将所有的权限信息去从加到集合中
expressionSet.add(p.getExpression());
}
//获取到所有贴了RequiredPermission注解,取出注解上的name和expression,
// 封装成Permission,保存到数据库中
//HandlerMethod代表每一个控制的方法引用
Map<RequestMappingInfo, HandlerMethod> handlerMethods = rmhm.getHandlerMethods();
Collection<HandlerMethod> values = handlerMethods.values();
for(HandlerMethod method:values){
// 获取方法的注解
RequiresPermissions annotation = method.getMethodAnnotation(RequiresPermissions.class);
// 方法上有贴我们的自定义权限注解
if (annotation != null) {
// 获取方法的注解 name 和 expression 值
String name = annotation.value()[1];
String expression = annotation.value()[0];
// 存入到数据库之前要判断一下, 若数据库中不存在就存入
if(!expressionSet.contains(expression)) {
Permission permission = new Permission();
permission.setName(name);
permission.setExpression(expression);
permissionMapper.insert(permission);
}
}
}
}
公告页面功能的实现
@Override
public Notice get(Long id) {
Notice notice = noticeMapper.selectByPrimaryKey(id);
//点击查看的时候中间表插入数据
noticeMapper.insertEmpNotice(UserContext.getEmployee().getId(),id);
return notice;
}
门店信息页面功能的实现
@RequiresPermissions(value = {"business:saveOrUpdate","门店编辑"}, logical = Logical.OR)
public String saveOrUpdate(Business business, MultipartFile file) throws Exception {
if (file != null && file.getSize()>0) {
//处理上传的操作
String realPath = servletContext.getRealPath("/");
//如果存在 编辑的时候上传带就把之前的删除
if (StringUtils.hasText(business.getLicenseImg())) {
//拼出删除的路径
String deletePath = realPath + business.getLicenseImg();
FileUploadUtil.deleteFile(deletePath);
}
String filePath = FileUploadUtil.uploadFile(file, realPath);
business.setLicenseImg(filePath);
}
if (business.getId() == null) {
businessService.save(business);
} else {
businessService.update(business);
}
return "redirect:/business/list";
}
预约信息页面功能的实现
//修改预约单状态功能
@RequestMapping("/updateStatus")
public String updateStatus(Long id ,Integer status){
appointmentService.updateStatus(id,status);
return "redirect:/appointment/list";
}
void updateStatus(@Param("id") Long id, @Param("status") Integer status);
<update id="updateStatus">
update appointment
set status = #{status}
where id = #{id}
</update>
七、论文参考:
八、项目总结:
在本次毕业设计期间,自己学会了很多新技术。以前百度开发技术的时候总觉得这些东西了解一下就好了,到时候不是手到擒来的事情吗。通过这次毕业设计项目的开发才真正认识到一个技术如果仅仅只是了解,那么你就只能说出技术的要点,让你真正去实现就会发现比登天都难。其实计算机方面的知识重在实践,只有你真正的把这些技术用熟才能说是对其的了解。
但是由于是第一次自己手动开发一个整套的基于SSM框架的项目,所以系统的问题还是有很多的。例如前端页面选取问题上,本人是采用了各个框架技术的模板页面;数据库中表的设计可能也会存在关系错乱的问题。但是在这次开发过程中也收获了很多之前没有的开发经验。对Bootstrap、Jquery、Freemarker、mybatis等框架或者技术有了更深层次的认识。同样也为自己毕业以后的学习生活和工作打下了坚实的基础。
在本次设计中收获最大的其实并不是对技术的掌握,而是了解到开发一个项目必须得做好规划。不能像无头苍蝇一般没有头绪,只有把项目的全部流程详细的规划好,用文档去记录起来,然后一步一步的实现项目的需求才能让系统具有生命。在开发过程中也不会一帆风顺,遇到系统出现问题的时候,我从以前的束手无策变成现在的冷静也得益于此次开发。现在的我遇到问题都会先分析系统的流程情况,再根据流程情况去分析代码实现的逻辑问题,实在解决不了就会借助百度的力量。当问题十分棘手的情况下会选择询问毕设导师周少波老师请求帮助。我觉得在毕业之后的工作时也应该有这样的态度,才能真正去把项目开发好。
本次毕业设计所做出的项目可能还无法满足真正的企业要求,与真正实际应用还是有着一定的差距的。原因在于搜集的信息不够充足、对实际情况了解不够深入、对系统的分析不够彻底。但是有了这次的开发经验,我相信在以后的开发之路上我能避免走很多弯路,也能开发出真正能应用于现实生活中的项目系统。
九、源码获取:
大家点赞、收藏、关注、评论啦 、查看👇🏻👇🏻👇🏻获取联系方式👇🏻👇🏻👇🏻
链接点击直达:下载链接