IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【毕业设计开源】基于SSM的实体商城商户在线租赁以及信息管理系统的设计与实现 -> 正文阅读

[Java知识库]【毕业设计开源】基于SSM的实体商城商户在线租赁以及信息管理系统的设计与实现

毕业时写的毕业设计,因为毕业后论文还有可能被复查,若大家的论文是原创,建议大家毕业几年后再进行开源

本设计包含了 多人在线聊天室,微信扫码支付,在线签字,PDF合同在线生成,商户评分,基本的商铺信息管理,合同管理,新闻和公告管理,用户管理等功能,具体功能请参看论文中截图

1 绪论

1.1?课题背景

在我国城市化高速发展的今天,各种规模的商城相继出现。商城需要招商,进驻商家进行经营,商城的商铺需要出租和管理,商城各经营场所的招商信息,公告信息和活动信息的发布,进驻商家的各种信息的管理,都是人工手动进行管理的,既没有效率又容易出错,查找起来更是相当的麻烦。基于上述原因,需要借助于一款基于Web的商城商户信息管理系统,便于商铺的在线出租和对商城,商家,商铺的信息的查询与管理,有利于营造良好的商城营商环境,减轻商城管理人员的工作强度,因此设计一款基于Web的商城商户信息管理系统具有较好的实用价值。

1.2 实现技术

IntelliJ IDEA:是java编程语言开发的集成环境。在业界被公认为最好的java开发工具,尤其在智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是非常优秀的。

SSM框架:由Spring,SpringMVC,MyBatis组成的框架集,是一个优秀的web项目框架,是继SSH之后,目前比较主流的Java EE企业级框架。Spring的目的就是用来替代更加重量级的的企业级Java技术,用来简化java的开发难度。SpringMVC是在Spring框架内置的MVC实现的一个子框架,可以轻松的实现MVC架构的程序设计。MyBatis 是一个持久层框架,他可以灵活的书写SQL语句,他让我们省略了大部分的JDBC代码、设置参数和获取结果集的代码。只使用简单的XML 和注解来映射基本数据类型、Map 接口和POJO 到数据库记录。

Maven:基于项目对象模型(POM project object model)的一个强大的项目管理工具,可以通过pom.xml文件配置智能的管理jar包

WebSocket:是一种在单个TCP连接上进行全双工通信的协议,允许服务端主动向客户端推送数据。本设计使用WebSocket技术实现聊天大厅的功能。

Druid连接池:阿里巴巴开源平台上的一个项目,能够提供强大的监控和扩展功能,可以替换DBCP和C3P0连接池,提供了一个高效、功能强大、可扩展性好的数据库连接池。

2 需求分析

2.1 可行性分析

2.1.1 技术可行性

SSM框架是spring MVC,spring和mabatis框架的整合,是标准的MVC模式,将整个系统划分为表现层,controller层,service层,DAO层四层,是一个成熟的企业级应用开发框架,而且在性能方面,要优于大部分编程语言,跨平台性更是实现了一次编译,到处运行。

2.1.2 经济可行性

传统模式的店铺租赁,需要提前查看选定商铺,然后联系出租方,约定时间后,需要双方同时到达同一个地方,仔细阅读合同后,进行签字并支付现金。然后管理者手动进行记录,这种方式既费时又费力。将挑选店铺,签订合同,支付等集合在一起的本系统,可以省去这些麻烦,并且管理者可以更好的进行管理。

2.1.3 操作可行性

系统使用常见的,用户熟悉的友好界面,使用常见的编辑框,按钮等组件,不仅界面美观,而且容易操作,只要是会操作电脑即可使用。本系统简化了许多的操作逻辑,大部分操作只需要点击鼠标即可操作完成。

2.2?流程分析

图3-1?用户流程

图3-2?管理员流程

2 概要设计

2.1 系统概要

基于Web的商城商户信息管理系统,采用MVC设计模式,整体使用Maven管理项目,后端使用SSM框架(Spring,SpringMVC,Mybits),前端使用HTML5,Layui,jQuery,CSS3,聊天大厅使用WebSocket技术,数据库使用MySQL配合阿里的Druid连接池,使用Spring声明式事务管理,设计并实现的一个集商铺在线出租,商铺搜索,合同在线手写签字,合同在线生成,在线支付,聊天大厅,入驻商家展示评分,用户管理,商家管理,商铺管理,首页Banner管理,商城公告活动的发布和管理,合同审核等功能的系统。

2.2 功能概要

基于Web的商城商户信息管理系统主要分为三个部分

1.管理部分:超级管理员对管理员的管理,管理员对用户的管理,管理员对商铺的管理,管理员对商家的管理,管理员对合同的管理,管理员对活动和公告的管理。

2.用户部分:用户查看商铺,用户租赁商铺,用户签订合同,用户对租赁的商铺的管理,用户之间的聊天

3.顾客部分:顾客可以对商家进行评论留言和评分,可以浏览店铺排行榜

2-1 系统功能

2.3 数据库设计

2.3.1 E-R图

2-2?用户E-R

2-3?管理员E-R

2-4?商铺E-R

2-5?公告E-R

2-6?合同E-R

2-7?E-R

2.3.2 数据库表结构

列 ??名

字段名称

类型

主键

可否为空

uid

用户ID?

INT(32)

username

用户名

VARCHAR(32)

password

用户密码

VARCHAR(32)

nickname

用户昵称

VARCHAR(32)

telephone

手机号

VARCHAR(11)

sex

性别

VARCHAR(1)

email

邮箱

VARCHAR(32)

pic

用户头像保存路径

VARCHAR(32)

idcard

身份证

VARCHAR(18)

表2-1 用户表(user)

表2-2 管理员表(admin)

列 ??名

字段名称

类型

主键

可否为空

id

管理员ID?

INT(32)

username

管理员名

VARCHAR(32)

password

管理员密码

VARCHAR(32)

quanxian

管理员权限等级

VARCHAR(32)

表2-3 商铺表(shops)

列 ??名

字段名称

类型

主键

可否为空

sid

商铺ID?

INT(32)

sname

商铺名

VARCHAR(32)

location

商铺位置

VARCHAR(32)

area

商铺面积

VARCHAR(32)

price

商铺价格/月

DECIMAL(10)

information

简介

VARCHAR(255)

details

详细介绍

VARCHAR(255)

state

商铺状态

INT(1)

pic

商铺封面图

VARCHAR(255)

pics

商铺图集

VARCHAR(255)

stime

营业时间

VARCHAR(32)

score

商铺评分

DOUBLE(3)

type

商铺分类

INT(1)

userid

当前租赁用户id

INT(32)

表2-4 合同表(contract)

列 ??名

字段名称

类型

主键

可否为空

id

合同ID?

VARCHAR(32)

userid

用户ID

INT(32)

shopid

商铺ID

INT(32)

name

用户姓名

VARCHAR(32)

starttime

开始时间

VARCHAR(32)

endtime

到期时间

VARCHAR(32)

contract

合同保存路径

VARCHAR(255)

state

合同状态

INT(1)

price

合同金额

DECIMAL(10)

表2-5 公告和活动表(announcement)

列 ??名

字段名称

类型

主键

可否为空

id

公告ID?

INT(32)

title

公告标题

VARCHAR(255)

content

公告内容

VARCHAR(9999)

type

公告类型

INT(1)

time

开始时间

DATETIME

表2-6 轮播图信息表(banner)

列 ??名

字段名称

类型

主键

可否为空

id

ID

INT(32)

img

图片路径

VARCHAR(255)

target

链接地址

VARCHAR(255)

表2-7 评论表(comment)

列 ??名

字段名称

类型

主键

可否为空

id

评论ID

INT(32)

shopid

店铺ID

INT(32)

name

评论者昵称

VARCHAR(32)

content

评论内容

VARCHAR(255)

score

评分

VARCHAR(10)

time

评论时间

DATETIME

表2-8 聊天记录表(chatgroup)

列 ??名

字段名称

类型

主键

可否为空

id

记录ID

INT(32)

nickname

用户昵称

VARCHAR(32)

username

用户名

VARCHAR(32)

content

记录内容

VARCHAR(255)

pic

头像地址

VARCHAR(255)

date

记录时间

DATETIME

3 详细设计

3.1?用户部分

3.1.1 用户注册

功能描述:

用户注册是用户通过手机号或者邮箱,注册为系统用户,填写用户名,手机时,使用Ajax后台判断是否已经注册过,并给出提示,避免重复注册。使用手机号码注册时,填入手机号,点击获取验证码按钮,验证码就会发送到手机,填入验证码即可注册成功。使用邮箱注册时,填入自己的邮箱地址,点击获取验证码,验证码就会发送到你的邮箱中,填入邮箱中的验证码即可注册成功。

图3-1?用户注册界面

?

图3-2?注册用户名已存在

Service层:

public ResultInfo register(User user) {

???// 校验用户名

???User u1 = userDao.findByUsername(user.getUsername());

???if (u1 != null) {

??????return new ResultInfo(false, "用户名已存在");

???}

???// 校验手机号

???User u2 = userDao.findByTelephone(user.getTelephone());

???if (u2 != null) {

??????return new ResultInfo(false, "手机号已存在");

???}

???// 校验邮箱

???User u3 = userDao.findByEmail(user.getEmail());

???if (u3 != null) {

??????return new ResultInfo(false, "邮箱已存在...");

???}

???// 密码加密

???String md5Password = Md5Utils.encodeByMd5(user.getPassword());

???user.setPassword(md5Password);

???// 保存用户

???userDao.save(user);

???return new ResultInfo(true);

}

Controller层

// 用户注册

????@RequestMapping(value ="/register",produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo register(User user, String smscode,String emailcode,Integer type) {

????????if(type==1) {

????????????// 手机验证码

????????????String sessionCode = (String) session.getAttribute("smsCode_" + user.getTelephone());

????????????if (sessionCode == null || !sessionCode.equals(smscode)) {

????????????????return new ResultInfo(false, "手机验证码错误!");

????????????}

????????}else if(type==2)

????????{ ??//邮箱验证码

????????????String sessionCode = (String) session.getAttribute("emailCode_" + user.getEmail());

????????????if (sessionCode == null || !sessionCode.equals(emailcode)) {

????????????????return new ResultInfo(false, "邮箱验证码错误!");

????????????}

????????}else{

????????????return new ResultInfo(false, "其他错误!");

????????}

????????// 调用service完成注册 ?昵称默认为用户ID

????????user.setNickname("用户"+user.getUid());

????????ResultInfo resultInfo = userService.register(user);

????????// 进行判断和页面跳转

????????if (resultInfo.getCode()==0) {

????????????// 注册成功,清除session的验证码

session.removeAttribute("smsCode_"+user.getTelephone());

????????????session.removeAttribute("emailCode_" + user.getEmail());

????????????return new ResultInfo(true);

????????} else {

????????????// 注册失败

????????????return resultInfo;

????????}

}

3.1.2 用户登录

功能描述:

用户使用注册的用户名和密码登录系统,或者使用注册时的手机号,通过短信验证码登录系统。登录页面使用Ajax方式后台异步发送请求,在收到结果后可以直接提示成功或失败,不需要再跳转到其他页面,使用手机登录时,输入注册时使用的手机号,然后点击获取验证码按钮,验证码短信就会发送到手机上,输入验证码即可登录到系统。忘记密码可以使用此功能登录。或者使用密码找回功能找回密码。

图3-3?用户账号登录界面

?

图3-4?用户手机登录界面

Service层

密码登录:

public ResultInfo pwdLogin(User user) {

User u1 = userDao.findByUsername(user.getUsername());

if (null==u1) {

return new ResultInfo(false, "此用户不存在");

}

String md5Pwd = Md5Utils.encodeByMd5(user.getPassword());

if (!md5Pwd.equals(u1.getPassword())) {

return new ResultInfo(false, "密码不正确");

}

return new ResultInfo(true, "登录成功", u1);

}

短信验证码登录:

public ResultInfo smsLogin(String telephone) {

User u1 = userDao.findByTelephone(telephone);

if (u1 == null) {

return new ResultInfo(false, "此手机号未注册");

}

return new ResultInfo(true, "登录成功", u1);

}

Controller层

密码登录:

/**

?????* 密码登录

?????* @param user 用户信息

?????* @param code 图形验证码

?????* @return ResultInfo

?????*/

????@RequestMapping(value = "/pwdLogin",produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo pwdLogin(User user,String code)

????{

????????String sessionCode = session.getAttribute("imgCode").toString();

????????if(code!=null && !"".equals(code) && code.toUpperCase().equals(sessionCode)) {

????????????ResultInfo resultInfo = userService.pwdLogin(user);

????????????if (resultInfo.getCode()==0) {

????????????????session.setAttribute("User", resultInfo.getData());

????????????????session.removeAttribute("imgCode");

????????????}

????????????return resultInfo;

????????}else{

????????????return new ResultInfo(false,"验证码错误!");

????????}

}

手机验证码登录:

/**

?????* 手机登录

?????* @param telephone 电话

?????* @param smscode 验证码

?????* @return ResultInfo

?????*/

????@RequestMapping(value = "/smsLogin",produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo smsLogin(String telephone,String smscode)

????{

????????String code = (String) session.getAttribute("smsCode_" + telephone);

????????if(code!=null && !"".equals(code) && code.equals(smscode)) {

????????????ResultInfo resultInfo = userService.smsLogin(telephone);

????????????// 写入session

????????????if (resultInfo.getCode()==0) {

????????????????session.setAttribute("User", resultInfo.getData());

????????????????session.removeAttribute("smsCode_"+telephone);

????????????}

????????????return resultInfo;

????????}else{

????????????return new ResultInfo(false,"验证码错误!");

????????}

????}

3.1.3 找回密码

功能描述:

用户忘记密码后通过此功能可找回密码,可以通过注册时使用的手机找回,也可以使用注册时使用的邮箱找回,在使用手机找回时,输入注册时使用的手机号,点击获取验证码按钮,手机将会收到一条验证码信息,输入验证码后进入下一步,通过邮箱找回时,点击获取验证码按钮,邮箱将会收到验证码,输入验证码信息也可进入下一步。

图3-5?找回密码界面

输入验证码后,就来到了此界面,自动查询出手机或邮箱绑定的用户名,防止用户因忘记用户名而无法登录,然后在下方输入新的密码,确认新的密码,点击重置密码按钮即可重置完成密码操作。

图3-6?确认找回密码界面

Service层

public User forget(User user) {

if(user.getTelephone()!=null)

{

return userDao.findByTelephone(user.getTelephone());

}else if(user.getEmail()!=null)

{

return userDao.findByEmail(user.getEmail());

}

return null;

}

Controller层

????@RequestMapping("/forget")

????public String forget(User user, String smscode,String emailcode,Integer type) {

????????Integer smsId = 1;

????????Integer emailId = 2;

????????if(user==null||type==null)

????????{

????????????request.setAttribute("errormsg","非法访问!");

????????????return "/error.jsp";

????????}

????????if(type.equals(smsId)) {

????????????// 手机验证码

????????????String sessionCode = (String) session.getAttribute("smsCode_" + user.getTelephone());

????????????if (sessionCode == null || !sessionCode.equals(smscode)) {

????????????????request.setAttribute("errormsg","手机验证码错误!");

????????????????return "/error.jsp";

????????????}

????????}else if(type.equals(emailId))

????????{ ??//邮箱验证码

????????????String sessionCode = (String) session.getAttribute("emailCode_" + user.getEmail());

????????????if (sessionCode == null || !sessionCode.equals(emailcode)) {

????????????????request.setAttribute("errormsg","邮箱验证码错误!");

????????????????return "/error.jsp";

????????????}

????????}else{

????????????request.setAttribute("errormsg","其他错误!");

????????????return "/error.jsp";

????????}

????????session.setAttribute("fUser",userService.forget(user));

????????return "/forgetChange.jsp";

????}

????/**

?????* 找回密码第二步,改密码

?????* @param password 新密码

?????* @return ResultInfo

?????*/

????@RequestMapping(value = "/forgetChange", produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo forgetChange(String password,String rePassword) {

????????if(!password.equals(rePassword)) {

????????????return new ResultInfo(false,"两次密码不一致!");

????????}

????????User user = (User) session.getAttribute("fUser");

????????if(user==null)

????????{

????????????return new ResultInfo(false,"非法请求!");

????????}

????????user.setPassword(Md5Utils.encodeByMd5(password));

????????userService.updateInfo(user);

????????session.removeAttribute("fUser");

????????return new ResultInfo(true);

}

3.2?个人中心

3.2.1 个人信息

功能描述:

在此页面,可以查看和修改用户的基本信息。包括姓名,手机号,邮箱,性别,身份证等信息,采用Ajax的方式提交到服务器,可以在页面上通过信息框提示是否更新成功,不必跳转页面。

图3-7?个人信息界面

Controller层

????@RequestMapping(value = "/updateInfo", produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo updateInfo(User user){

????????userService.updateInfo(user);

????????//重新写入session

????????User u1 = userService.findByUid(user.getUid());

????????session.setAttribute("User", u1);

????????return new ResultInfo(true);

}

3.2.2 更换头像

功能描述:

更换头像功能,可以更换用户的头像图片,首先点击上传头像按钮,弹出选择文件对话框,选中要上传的头像图片,点击确定,方框中就会显示选择的图片,此时,头像图片并未上传至服务器,而是读取了文件的内容,将其显示在浏览器中,当点击提交头像时,图片才被送到服务器中保存。

图3-8?更换头像界面

Controller层

????@RequestMapping(value = "/updatePic", produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo updatePic(MultipartFile file) throws IOException {

????????if (!file.isEmpty()) {

????????????User user = (User) session.getAttribute("User");

????????????if (user != null) {

????????????????String picPath = "/pic/" + user.getUid() + ".jpg";

????????????????File myFile = new File(request.getServletContext().getRealPath("/") + picPath);

????????????????file.transferTo(myFile);

????????????????user.setPic(picPath);

????????????????userService.updateInfo(user);

????????????????//重新写入session

????????????????User u1 = userService.findByUid(user.getUid());

????????????????session.setAttribute("User", u1);

????????????????return new ResultInfo(true);

????????????}

????????????return new ResultInfo(false);

????????}

????????return new ResultInfo(false);

}

前端

layui.use('upload', function(){

var $ = layui.jquery

????????,upload = layui.upload;

//头像上传

var uploadInst = upload.render({

??elem: '#test1'

??,url: '${pageContext.request.contextPath}/user/updatePic' //上传接口

??,bindAction:'#test2'//执行文件上传动作

??,auto: false

??,choose:function (obj) {

????obj.preview(function(index, file, result){

??????$('#demo1').attr('src', result); //图片转为base64赋给src属性

????});

??}

??,done: function(res){

????//如果上传失败

????if(res.code > 0){

??????return layer.msg('上传失败');

????}

????//上传成功

????$('#touxiang').attr('src', '${pageContext.request.contextPath}/${User.pic}?'+new Date().getTime());

????$('#htouxiang').attr('src', '${pageContext.request.contextPath}/${User.pic}?'+new Date().getTime());

????return layer.msg('上传成功');

??}

??,error: function(){

????//失败重传

????var demoText = $('#demoText');

????demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');

????demoText.find('.demo-reload').on('click', function(){

??????uploadInst.upload();

????});

??}

});

})

3.2.3 修改密码

功能描述:

用户的修改密码功能,输入自己的旧密码,然后输入新密码,确认新密码,点击确认修改按钮,即可成功修改密码。修改密码后,登录信息将失效,需要重新登录,自动打开登录窗口,并提示用户重新登录。

图3-9?修改密码界面

Controller层

@RequestMapping(value = "/updatePass", produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo updatePass(String oldPassword,String newPassword,String againPassword) {

????ResultInfo result;

????if (!newPassword.equals(againPassword)) {

????????result = new ResultInfo(false, "两次密码输入不一致!");

????} else {

????????User user = (User) session.getAttribute("User");

????????if (user != null) {

????????????if (user.getPassword().equals(Md5Utils.encodeByMd5(oldPassword))) {

????????????????if (oldPassword.equals(newPassword)) {

????????????????????result = new ResultInfo(false, "旧密码不能与新密码一致!");

????????????????} else {

????????????????????user.setPassword(Md5Utils.encodeByMd5(newPassword));

????????????????????userService.updateInfo(user);

????????????????????session.removeAttribute("User");

????????????????????result = new ResultInfo(true);

????????????????}

????????????} else {

????????????????result = new ResultInfo(false, "旧密码输入错误!");

????????????}

????????} else {

????????????result = new ResultInfo(false, "非法请求!");

????????}

????}

????return result;

}

3.2.4 用户合同管理

功能描述:

用户合同管理功能,在此页面中,可以看到当前用户所签订的所有合同信息,包括(合同编号,合同商铺,开始时间,终止时间,成交价格,合同状态),并且可以下载合同源文件。合同状态分别为 未付款,审核中,已生效,已过期 四个状态。由系统内的定时任务自动管理,每十分钟刷新一次状态。在已生效和已过期状态时,可以下载合同,未支付状态时,可以跳转到付款页面。

图3-10?我的合同界面

Controller层

????@RequestMapping("/userHetong")

????public String userHetong(){

????????User user = (User) session.getAttribute("User");

????????if (user == null){

????????????return "redirect:/index.jsp";

????????}else{

????????????List<Contract> contracts = contractService.findByUserid(user.getUid());

????????????request.setAttribute("contracts",contracts);

????????????return "/home_hetong.jsp";

????????}

}

3.2.5 用户商铺管理

功能描述:

用户商铺管理功能,在此页面中,可以看到用户正在经营的商铺信息,包括商铺编号,商铺名称,商铺位置,商铺面积 ,商铺类型,营业时间 ,商铺评分等信息。评分由顾客评价后给出的评分根据一定算法进行计算,用户只能看到分数。同时,用户可以编辑商铺的信息,包括名称,类型,营业时间,简介,详细介绍,封面图,图集等内容。在租赁商铺后可以更新为自己所经营的信息。

图3-11?我的商铺界面

Controller层

????@RequestMapping("/userShop")

????public String userShop(){

????????User user = (User) session.getAttribute("User");

????????if (user == null){

????????????return "redirect:/index.jsp";

????????}else{

????????????List<Shop> shops = shopService.findShopsByUid(user.getUid());

????????????request.setAttribute("shops",shops);

????????????return "/home_shop.jsp";

????????}

}

????@RequestMapping("/editShop/{sid}")

????public String editShop(@PathVariable("sid") Integer sid)

????{

????????User user = (User) session.getAttribute("User");

????????if(user==null)

????????{

????????????return "/Login.jsp";

????????}

????????Shop shop = shopService.findShopsBySid(sid);

????????if(shop.getUserid()==user.getUid())

????????{

????????????request.setAttribute("Shop",shop);

????????????return "/home_shop_edit.jsp";

????????}

????????return null;

????}

????@RequestMapping(value = "/setShop", produces = "application/json;charset=utf-8")

????@ResponseBody

????public ResultInfo setShop(Shop shop){

????????User user = (User) session.getAttribute("User");

????????if(user==null)

????????{

????????????return new ResultInfo(false);

????????}

????????return shopService.update(shop);

????}

3.3?商铺租赁

3.3.1 出租商铺展示

功能描述:

展示当前正在出租的商铺信息,包括位置,价格,面积,详细介绍等。可选择租赁期限,点击立即租赁,即可进入商铺租赁流程。若当前未登录账号,则弹出账号登录模态框,登录账号后依然停留在本页面,可以继续操作。

图3-12?商铺列表页

图3-13?商铺详情页

ShopsController层

@RequestMapping("/rent")

public String rent(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "12") Integer pageSize) {

????PageBean pageBean = shopsService.listRent(pageNum, pageSize);

????request.setAttribute("pb", pageBean);

????return "/rent_list.jsp";

}

ShopSevice层

public PageBean listRent(Integer pageNum, Integer pageSize)

{

Integer total = shopsDao.findRentCount();

Integer index = (pageNum - 1) * pageSize;

List<Shop> list = shopsDao.findRentByPage(index, pageSize);

return new PageBean(total, list, pageNum, pageSize);

}

前端

<div class="layui-row layui-col-space10">

??<s:if test="${empty pb.data}">

????<div style="text-align: center;padding-top: 50px">暂无商家</div>

??</s:if>

??<s:forEach items="${pb.data}" var="shop">

????<div class="layui-col-md3 layui-col-sm4">

??????<div class="item">

????????<a href="${pageContext.request.contextPath}/detail/${shop.sid}">

??????????<img width="100%" height="200px" src="${pageContext.request.contextPath}${shop.pic}">

????????</a>

????????<a href="${pageContext.request.contextPath}/detail/${shop.sid}">

??????????<div style="height:47px;padding: 2px">

????????????<p class="text">${shop.sname}</p>

????????????<div class="layui-row">

??????????????<div class="layui-col-xs8 layui-col-md9 layui-col-lg10">

????????????????<b>${shop.stime}</b>

??????????????</div>

??????????????<div class="layui-col-xs4 layui-col-md3 layui-col-lg2" style="text-align: right;color: red">

????????????????<b>${shop.score}</b>

??????????????</div>

????????????</div>

??????????</div>

????????</a>

??????</div>

????</div>

??</s:forEach>

</div>

3.3.2 签署租赁合同

功能描述:

租赁商铺时,选择好商铺和租赁时间,点击立即租赁后,即可进入在线签署租赁合同页面,生成合同内容,用户在详细阅读合同后,在下方签字处手写签字,然后点击提交,即可完成签署合同。用户提交后,后台使用itext组件,生成PDF文档,并将签名插入到指定位置,保存在/pdf目录下。同时修改商铺状态为已被租赁,然后跳转到支付页面,用户进行支付操作。若用户未完成支付操作,没有商铺操作权限,若用户10分钟后仍未完成支付,商铺将被系统回收,重置为租赁状态。

图3-14?签署合同页

Controller层

@RequestMapping("/create")

public String nameimg(Integer sid,String starttime,String endtime, String namepic,Double price) {

????User user = (User) session.getAttribute("User");

????if(user!=null && !"".equals(namepic))

????{

????????Shop shop = shopsService.findShopsBySid(sid);

????????String picPath = "upload\\" + Md5Utils.encodeByMd5(namepic) + ".png";

????????String realPicPath = request.getServletContext().getRealPath("/") + picPath;

????????Base64Util.base64ToImage(namepic,realPicPath);

????????String path = "pdf/"+UUID.randomUUID()+".pdf";

????????String savepath = request.getServletContext().getRealPath("/") +path;

????????Contract contract = new Contract();

????????contract.setId(UuidUtils.getUuid());

????????contract.setName(user.getNickname());

????????contract.setUserid(user.getUid());

????????contract.setShopid(shop.getSid());

????????contract.setStarttime(starttime);

????????contract.setEndtime(endtime);

????????contract.setContract(path);

????????contract.setState(0);

????????contract.setPrice(price);

????????/*添加合同记录 并 修改店铺状态和userid*/

????????contractService.add(contract,shop,user);

????????try{

????????????PdfUtil.createPDF(user.getNickname(),shop.getLocation(),shop.getArea(),starttime,endtime,price.toString(),NumToCnUtil.toChinese(price.toString()),realPicPath,savepath);

????????}catch (Exception e)

????????{

????????????request.setAttribute("errormsg","合同生成失败!");

????????????return "/error.jsp";

????????}

????????return "redirect:/contract/pay/"+contract.getId();

????}

????return "/error.jsp";

}

Service层

public void add(Contract contract, Shop shop, User user)

{

contractDao.save(contract);

shop.setState(2);

shop.setUserid(user.getUid());

shopsDao.update(shop);

}

前端

$(function () {

??$("#box").jSignature();//初始化画板

});

layui.use('form', function(){

??var form = layui.form;

??//监听表单提交

??form.on('submit(tijiao)', function (data) {

????var datapair = $("#box").jSignature("getData","image");

????$("#namepic").val(datapair[1]);

????return true;

??});

});

function chongxie(){

??$("#box").jSignature("reset");

??$("#image").attr('src','');

}

3.3.3 在线支付

功能描述:

本功能调用微信支付完成,签完合同后,弹出支付页面,用户使用手机扫码在线支付。在支付时,后台使用定时器每秒钟查询一次支付状态,若支付成功,跳转到成功页面,在线支付完成。若超时10分钟未支付,页面提示超时,订单将被删除,商铺被回收,重新置为租赁状态。若支付成功,商铺进入审核状态,后台管理员审核通过后,即可正常使用。

图3-15?在线支付页

Controller层

@RequestMapping("/pay/{id}")

public String pay(@PathVariable("id") String id)

{

????Contract contract = contractService.findByid(id);

????if(contract!=null)

????{

????????String payurl = PayUtils.createOrder(id,contract.getPrice()*100); //支付金额 单位:分

????????request.setAttribute("payUrl",payurl);

????????request.setAttribute("contract",contract);

????????return "/pay.jsp";

????}else{

????????request.setAttribute("errormsg","订单不存在!");

????????return "/error.jsp";

????}

}

/**

?* 支付成功回调

?* @return

?* @throws Exception

?*/

@RequestMapping(value = "/payNotify", produces = MediaType.APPLICATION_XML_VALUE)

@ResponseBody

public Map<String, String> payNotify() throws Exception

{

????ServletInputStream inputStream = request.getInputStream();

????XmlMapper xmlMapper = new XmlMapper();

????Map param = xmlMapper.readValue(inputStream, Map.class);

????contractService.updateState(param);

????Map<String, String> result = new HashMap<>(10);

????result.put("return_code", "SUCCESS");

????result.put("return_msg", "OK");

????return result;

}

/**

?* 查看支付状态

?*/

@RequestMapping(value = "/checkPay",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo checkPay(String id) {

????Contract contract = contractService.findByid(id);

????if (contract.getState() == 1) {

????????return new ResultInfo(true);

????} else {

????????return new ResultInfo(false);

????}

}

Service层

public void updateState(Map param) {

//支付成功通知的订单号

String orderId = (String) param.get("out_trade_no");

Contract contract = contractDao.findById(orderId);

contract.setState(3);

contractDao.update(contract);

}

前端

生成二维码

??var qr = window.qr = new QRious({

????element: document.getElementById('qrious'),

????size: 300,

????value: '${payUrl}'

??});

10分钟倒计时

var num=60*10;

setInterval(function () {

??// 发送ajax请求,查询是否支付成功

??var url = '${pageContext.request.contextPath}/contract/checkPay?id=${contract.id}';

??$.get(url, function (resp) {

????if (resp.code==0) {

??????location.href = '${pageContext.request.contextPath}/success.jsp';

????}

??});

??num--;

??$('#jishiqi').html(parseINT(num/60)+'分'+num%60+'秒后失效,请及时付款!')

}, 1000);

超时跳转到错误页

setTimeout(function () {

??location.href = '${pageContext.request.contextPath}/error.jsp';

}, 600000);

3.4?商家展示

3.4.1 入驻商家展示

功能描述:

列表页展示入驻的全部商家,分页显示,按照评分从高到低排名,也可以按商家分类展示。详情页展示已经在本商城入驻的商家信息,包括简介,商家位置,分类,营业时间,商家评分,详细介绍等。

图3-16?商家列表页

图3-17?商家详情页

Controller层

商家列表

@RequestMapping("/shop")

public String shop(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "12") Integer pageSize,@RequestParam(defaultValue = "-1") Integer type) {

????PageBean pageBean;

????if(type==-1)

????{

????????pageBean = shopsService.listShop(pageNum, pageSize);

????}else{

????????pageBean = shopsService.listShop(pageNum, pageSize,type);

????}

????request.setAttribute("pb", pageBean);

????return "/shop_list.jsp";

}

商家详情

@RequestMapping("/detail/{sid}")

public String detail(@PathVariable("sid") Integer sid) {

????Shop shop = shopsService.findShopsBySid(sid);

????request.setAttribute("shop", shop);

????if(shop.getState()==1)

????{

????????List<Comment> comments = commentService.findByShopid(sid);

????????request.setAttribute("Comments", comments);

????????return "/shop_detail.jsp";

????}else{

????????return "/rent_detail.jsp";

????}

}

Service层

public PageBean listShop(Integer pageNum, Integer pageSize)

{

Integer total = shopsDao.findShopCount();

Integer index = (pageNum - 1) * pageSize;

List<Shop> list = shopsDao.findShopByPage(index, pageSize);

return new PageBean(total, list, pageNum, pageSize);

}

3.4.2 评论商家

功能描述:

顾客可以对已经入驻的商家进行留言评论和评分,商家评分根据顾客的评分按照评分公式自动计算,商家无法修改。若评分小于等于1星,商家将被警告。

图3-18?商家详情页评论

Controller层

@RequestMapping(value="/shop/comment",produces = "application/json")

@ResponseBody

public ResultInfo comment(Comment comment)

{

????commentService.save(comment);

????return new ResultInfo(true);

}

Service层

public void save(Comment comment) {

????comment.setTime(new Date());

????commentDao.save(comment);

}

前端

<form class="layui-form layui-form-pane" action="">

??<input name="shopid" type="hidden" value="${shop.sid}">

??<input id="score" name="score" type="hidden" value="5">

??<input id="content" name="content" type="hidden">

??<div class="">

????<div id="myEditor" style="display: none;"></div>

????<div class="layui-inline">

??????<label class="layui-form-label">姓名:</label>

??????<div class="layui-input-inline">

????????<input style="width: 150px" name="name" lay-verify="required" autocomplete="off" class="layui-input">

??????</div>

????</div>

????<div class="layui-inline">

??????<label style="margin-top: 3px" class="layui-form-label">评分:</label>

??????<div ?id="myPingFen"></div>

????</div>

????<div style="width: 200px;float:right" id="send" class="layui-btn" lay-submit lay-filter="pinglun-tijiao" >提交</div>

??</div>

</form>

<br><br>

<div class="layui-card-header">

??评论列表

</div>

<s:if test="${empty Comments}">

??<div id="noping" class="layui-card">

????<div class="layui-card-body">暂无评论,快来评论吧!</div>

??</div>

</s:if>

<div id="pinglist">

<s:forEach items="${Comments}" var="Comment">

??<div class="layui-card">

????<div class="layui-card-header"><b>${Comment.name}</b><img src="${pageContext.request.contextPath}/imgs/star/${Comment.score}.png" alt=""> ??( ${Comment.score}分 ) ?????<i style="color: #BBBBBB">${Comment.time}</i></div>

????<div class="layui-card-body">${Comment.content}</div>

??</div>

</s:forEach>

</div>

3.5?聊天大厅

聊天大厅使用WebSocket技术,实现聊天信息的实时传输。

图3-19?聊天大厅

3.5.1 配置监听路径

功能描述:

此处配置WebSocket的监听路径,聊天大厅连接此处监听的路径,可以向此路径发送数据,服务器监听向此路径发送的数据,收到数据后进行处理。

WebSocketConfig 配置

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(webSocketMessageHandler(),"/websocket").addInterceptors(new MyWebSocketHandshakeInterceptor());

registry.addHandler(webSocketMessageHandler(), "/sockjs/websocket").addInterceptors(new MyWebSocketHandshakeInterceptor()).withSockJS();

}

3.5.2 处理Sesssion

功能描述:

在websocket连接前,对websocket的session进行处理,添加httpsession里的有关用户登录认证的字段:User,以便在聊天大厅获取用户名等信息,将websocket的用户和网站用户联系起来。

WebSocketHandshakeInterceptor?握手拦截器

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

???????????????????????????????Map<String, Object> attributes) throws Exception {

????//Before Handshake--websocket 握手之前的方法

????if (request instanceof ServletServerHttpRequest) {

????????ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;

????????HttpSession httpSession = servletRequest.getServletRequest().getSession(false);

????????if (httpSession != null) {

????????????attributes.put("httpsession",httpSession);

????????????User user = (User) httpSession.getAttribute("User");

????????????if (user != null) {

????????????????attributes.put("userid", String.valueOf(user.getUid()));

????????????}else{

????????????????attributes.put("userid", "0");

????????????}

????????}

????}

????return super.beforeHandshake(request, response, wsHandler, attributes);

}

3.5.3 服务端消息处理

功能描述:

处理收到的聊天消息,定义了自己的发送规则,服务器向客户端发送消息时,使用mtype标志,mtype为1时,表示用户发送聊天消息。mtype为2时,表示系统发送提示信息。mtype为3时,表示用户上线。mtype为4时,表示用户下线。mtype为5时,表示发送在线用户列表。客户端向服务器发送消息时,使用ttype标志,ttype值为“消息”时,表示发送的是聊天消息。

WebSocketMessageHandler?消息处理器

@Component

public class WebSocketMessageHandler extends TextWebSocketHandler {

????@Autowired

private ChatGroupService chatGroupService;

????private static final Map<String, ChatUser> USERS = new ConcurrentHashMap<>();

????/**

?????* 建立连接后的处理

?????*/

????@Override

????public void afterConnectionEstablished(WebSocketSession session) throws Exception {

????????HttpSession httpsession = (HttpSession) session.getAttributes().get("httpsession");

????????if(httpsession!=null)

????????{

????????????User user = (User) httpsession.getAttribute("User");

????????????if(user!=null) {

????????????????ChatUser chatuser = new ChatUser();

????????????????chatuser.setUser(user);

????????????????chatuser.setSession(session);

????????????????USERS.put(String.valueOf(chatuser.getUser().getUid()), chatuser);

????????????????putChatList(String.valueOf(chatuser.getUser().getUid()));

????????????????putOnline(chatuser);

????????????}

????????}

????????super.afterConnectionEstablished(session);

????}

????/**

?????* 向所有用户发送用户下线

?????* @param cu ChatUser

?????*/

????private void putOffline(ChatUser cu)

????{

????????HashMap<String,Object> map = new HashMap<>(10);

????????map.put("mtype",4);

????????map.put("username",cu.getUser().getUsername());

????????sendMessageToAllUsers(JSONUtils.toJSONString(map));

????}

????/**

?????* 向所有用户发送用户上线

?????* @param cu ChatUser

?????*/

????private void putOnline(ChatUser cu)

????{

????????HashMap<String,Object> map = new HashMap<>(10);

????????map.put("mtype",3);

????????map.put("username",cu.getUser().getUsername());

????????map.put("nickname",cu.getUser().getNickname());

????????map.put("pic",cu.getUser().getPic());

????????sendMessageToAllUsers(JSONUtils.toJSONString(map),String.valueOf(cu.getUser().getUid()));

????}

????/**

?????* 向指定用户发送在线用户列表

?????* @param uid 用户ID

?????*/

????private void putChatList(String uid){

????????Map<String,Object> map = new HashMap<>(10);

????????Map<String,Object> map2 = new HashMap<>(10);

????????map.put("mtype",5);

????????map.put("count",USERS.size());

????????Integer i=0;

????????for(Map.Entry<String, ChatUser> entry : USERS.entrySet()){

????????????Map<String,Object> map3 = new HashMap<>(10);

????????????map3.put("nickname",entry.getValue().getUser().getNickname());

????????????map3.put("username",entry.getValue().getUser().getUsername());

????????????map3.put("pic",entry.getValue().getUser().getPic());

????????????map2.put(String.valueOf(i),map3);

????????????i++;

????????}

????????map.put("data",map2);

????????String json = ?JSONUtils.toJSONString(map);

????????try {

????????????USERS.get(uid).getSession().sendMessage(convertWebSocketTextMessage(json));

????????} catch (IOException e) {

????????????e.printStackTrace();

????????}

????}

????/**

?????* 连接关闭后的处理

?????* @param session 被关闭的session

?????* @param status 状态

?????* @throws Exception 发送失败异常

?????*/

????@Override

????public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

????????String userid = (String) session.getAttributes().get("userid");

????????//通知全部用户有人下线

????????if(userid!=null)

????????{

????????????putOffline(USERS.get(userid));

????????????USERS.remove(userid);

????????}

????????super.afterConnectionClosed(session, status);

????}

????/**

?????* 文本消息处理

?????* @param session 发送者session

?????* @param message 发送内容

?????*/

????@Override

????protected void handleTextMessage(WebSocketSession session, TextMessage message){

????????String typeMsg = "消息";

????????String userid = (String) session.getAttributes().get("userid");

????????String payload = message.getPayload();

????????@SuppressWarnings("unchecked")

????????HashMap<String, Object> map = (HashMap<String, Object>) JSONUtils.parse(payload);

????????String ttype = (String) map.get("ttype");

????????if(typeMsg.equals(ttype))

????????{

????????????Date d = new Date();

????????????SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

????????????map.put("date",sdf.format(d));

????????????map.put("mtype",1);

????????????putMessages(userid,map);

????????}

????}

????/**

?????* 向指定用户发送消息

?????* @param userid 用户id

?????* @param map 消息

?????*/

????private void putMessages(String userid, Map<String,Object> map)

????{

????????//保存聊天记录到数据库

????????ChatHistory chatHistory = new ChatHistory();

????????chatHistory.setNickname((String) map.get("nickname"));

????????chatHistory.setUsername((String) map.get("username"));

????????chatHistory.setPic((String) map.get("pic"));

????????chatHistory.setContent((String) map.get("content"));

????????chatHistory.setDate((String) map.get("date"));

????????chatGroupService.save(chatHistory);

????????for(Map.Entry<String, ChatUser> entry : USERS.entrySet()){

????????????WebSocketSession session = entry.getValue().getSession();

????????????if (session.isOpen()) {

????????????????try {

????????????????????map.put("isSelf",entry.getKey().equals(userid));

??????????????????session.sendMessage(convertWebSocketTextMessage(JSONUtils.toJSONString(map)));

????????????????} catch (IOException e) {

????????????????????e.printStackTrace();

????????????????}

????????????}

????????}

????}

????private TextMessage convertWebSocketTextMessage(String textMessage) {

????????return new TextMessage(textMessage);

????}

????/**

?????* 发送消息给所有用户

?????* @param textMessage 消息

?????*/

????private void sendMessageToAllUsers(String textMessage) {

????????for(Map.Entry<String, ChatUser> entry : USERS.entrySet()){

????????????WebSocketSession session = entry.getValue().getSession();

????????????if (session.isOpen()) {

????????????????try {

????????????????????session.sendMessage(convertWebSocketTextMessage(textMessage));

????????????????} catch (IOException e) {

????????????????????e.printStackTrace();

????????????????}

????????????}

????????}

????}

}

3.5.4 连接服务器

功能描述:

聊天大厅页面连接服务器,然后可以发送消息给服务器。使用两种连接方式,一种是HTML5的Websocket连接,若用户的浏览器不知吹HTML5,则使用SockJS来模拟Websocket连接,这样就可以兼容多种浏览器。因为Websocket无活动60秒后会自动断开连接,所以前端使用javascript设置一个定时器,每55秒发送一次心跳数据,用来保持Websocket连接,服务器无需回复这个信息。

var?wsPath='ws://${pageContext.request.getServerName()}:${pageContext.request.getServerPort()}${pageContext.request.contextPath}/';

var socket;

try {

????if ('WebSocket' in window) {

????????socket = new WebSocket(wsPath+"websocket");

????} else {

????????socket = new SockJS(wsPath+"sockjs/websocket");

????}

} catch (e) {

????console.log('创建连接失败!'+e);

}

socket.onmessage=function(ev){

var obj = eval('('+ev.data+')');

?????addMessage(obj)

};

setInterval(function () {

????var str = JSON.stringify({

????????ttype:'心跳'

????});

????socket.send(str);

},55000);

3.5.5 发送消息

功能描述:

用户在输入框输入内容后,点击发送按钮,聊天大厅使用JS判断用户是否登录,消息内容是否为空,通过后把消息内容拼接成json格式,然后通过Websocket发送给服务器。消息可以支持文字,表情,超链接,图片等格式。

$("#send").click(function(){

????var u = '${User}';

????if(u=='') {

????????layer.msg("您不能发送消息,请登录!");

????????return false;

????}

????var txt = layedit.getContent(index);

????if(txt==''||txt==' ') {

????????layer.msg("消息不能为空!");

????????return false;

????}

????var str = JSON.stringify({

????????nickname:nickname,

????????username:username,

????????pic:pic,

????????content:txt,

????????ttype:'消息'

????});

????if(isEmpty(txt))

????{

????????layer.msg("没有输入内容!");

????}else {

????????socket.send(str);

????????layedit.setContent(index,'');

????}

});

3.5.6 接收消息

功能描述:

客户端收到消息后,判断消息类型,mtype为1时代表是聊天消息。将接收到的聊天消息格式化后,填充到消息模板里,然后追加到容器中,显示在页面上,同时判断这条消息是不是自己发的,如果是,则不播放消息提示音,如果不是则播放收到消息的提示音,提醒用户收到消息。

var audio= new Audio("${pageContext.request.contextPath}/audio/default.mp3");

if(msg.mtype==1)

{

????var box = $("#msgtmp").clone();

????box.show();

????box.appendTo("#chatContent");

????box.find('[ff="nickname"]').html(msg.isSelf? ('<i>'+msg.date+'</i>'+msg.nickname+' ('+msg.username+')'):(msg.nickname+' ('+msg.username+')'+'<i>'+msg.date+'</i>'));

????box.find('[ff="pic"]').html('<img src="'+msg.pic+'">');

????box.find('[ff="msgdate"]').html(msg.date);

????box.find('[ff="content"]').html(msg.content);

????box.addClass(msg.isSelf? 'layim-chat-mine':'');

????scroll_To(1000);

????//不是自己发的消息播放叮咚声

????if(!msg.isSelf)

????{

????????audio.play();

????}

}

3.6?定时任务

定时任务主要处理的是长时间未支付的合同和计算过期合同,使用Spring框架的@Scheduled注解实现。定时任务是每隔一段时间自动运行一次的任务,启动后无需人工管理,即可自动执行。

3.6.1 未支付合同处理

功能描述:

定时处理超过支付时间但是仍未支付的合同订单。每10分钟扫描一次,若有超时未支付的合同订单,将相关联的商铺重新置为租赁状态,然后删除这个合同,将相关联的用户置为空。

private void timeOutTiming(){

????SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

????List<Contract> cons = contractService.findByNoPay();

????for (Contract con : cons) {

????????String starttime = con.getStarttime();

????????try{

????????????long startDate = format.parse(starttime).getTime();

????????????long nowDate = System.currentTimeMillis();

????????????long minute = (nowDate-startDate)/1000/60;

????????????if(minute>=10)

????????????{

????????????????//十分钟未支付,删除合同并恢复租赁

????????????????contractService.delete(con.getId());

????????????}

????????}catch (Exception e){

????????????e.printStackTrace();

????????}

????}

}

Service层

public ResultInfo delete(String id) {

//改为租赁状态

shopsDao.updateState(contractDao.findById(id).getShopid(),0);

shopsDao.updateUid(contractDao.findById(id).getShopid(),0);

contractDao.delete(id);

return new ResultInfo(true);

}

3.6.2 到期合同处理

功能描述:

定时处理到期合同,合同到期后,将商铺重置为过期审核状态,供后台管理员审核和修改,然后将合同置为过期状态,将相关联的用户置为空。

private void expiredTiming(){

????SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

????List<Contract> cons = contractService.findByValid();

????for (Contract con : cons) {

????????String endtime = con.getEndtime();

????????try{

????????????long endDate = format.parse(endtime).getTime();

????????????long nowDate = System.currentTimeMillis();

????????????long expired = nowDate-endDate;

????????????if(expired>0){

????????????????//合同过期 恢复租赁状态

????????????????contractService.updateStateById(con.getId(),2);

????????????}

????????}catch (Exception e){

????????????e.printStackTrace();

????????}

????}

}

Service层

public void updateStateById(String id,Integer state) {

Contract contract = contractDao.findById(id);

contract.setId(id);

contract.setState(state);

contractDao.update(contract);

//店铺租赁过期状态

shopsDao.updateState(contract.getShopid(),2);

shopsDao.updateUid(contract.getShopid(),0);

}

3.7?后台管理

3.7.1 最新合同审核

功能描述:

对用户提交的合同进行审核,在后台可以查看合同全部内容,验证合同内容和签字是否规范。对签字不规范的合同可以进行驳回处理,对签字规范的合同进行通过处理。

图3-20?最新合同审核页

图3-21?合同查看

Controller层

private boolean check(){

????Admin admin = (Admin) session.getAttribute("Admin");

????return admin != null;

}

@RequestMapping(value = "/data/getCheckCont",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getCheckCont(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return contractService.findCheckByPage(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setYesCont",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setYesCont(Contract contract)

{

????if(check()) {

????????Contract contract1 = contractService.findByid(contract.getId());

????????Shop shop = shopsService.findShopsBySid(contract1.getShopid());

????????shop.setState(1);

????????shopsService.addOrUpdate(shop);

????????contract.setState(1);

????????return contractService.addOrUpdate(contract);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/setNoCont",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setNoCont(Contract contract)

{

????if(check()) {

????????contract.setState(4);

????????return contractService.addOrUpdate(contract);

????}

????return new ResultInfo(false,"没有操作权限!");

}

Service层

public ResultInfo addOrUpdate(Contract contract) {

????Contract c = contractDao.findById(contract.getId());

????try {

????????if (c == null) {

????????????contractDao.save(contract);

????????} else {

????????????contractDao.update(contract);

????????}

????????return new ResultInfo(true);

????}catch (Exception e){

????????return new ResultInfo(false);

????}

}

public PageBean findCheckByPage(Integer pageNum, Integer pageSize) {

????Integer count = contractDao.findCheckCount();

????Integer index = (pageNum - 1) * pageSize;

????List<Contract> data = contractDao.findCheckByPage(index, pageSize);

????return new PageBean(count, data, pageNum, pageSize);

}

3.7.2 过期商铺审核

功能描述:

管理员对过期的商铺进行审核,重新设置商铺的相关信息,然后将商铺状态改为租赁状态,在网站上进行出租。先点击修改按钮,在弹出的窗口中重新设置店铺信息,然后点击出租按钮,即可进行出租。

图3-22?过期商铺审核页图

图3-23?过期商铺审核编辑页图

Controller层

@RequestMapping(value = "/data/getCheckRent",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getCheckRent(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return shopsService.listCheckRent(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setToRent",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setToRent(Shop shop)

{

????if(check()) {

????????return shopsService.updateState(shop.getSid(),0);

????}

????return new ResultInfo(false,"没有操作权限!");

}

Service层

public PageBean listCheckRent(Integer pageNum, Integer pageSize)

{

Integer total = shopsDao.findCheckRentCount();

Integer index = (pageNum - 1) * pageSize;

List<Shop> list = shopsDao.findCheckRentByPage(index, pageSize);

return new PageBean(total, list, pageNum, pageSize);

}

3.7.3 用户管理

功能描述:

管理员对商城注册用户的管理,可以添加用户,修改用户信息,删除用户等。

图3-24?用户管理页图

图3-25?用户管理修改页图

Controller层

@RequestMapping(value = "/data/getUser",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getUser(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return userService.findByPage(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setUser",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setUser(User user)

{

????if(check()) {

????????return userService.addOrUpdateUser(user);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delUser",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delUser(Integer id)

{

????if(check()) {

????????return userService.delUser(id);

????}

????return new ResultInfo(false,"没有操作权限!");

}

Service层

public PageBean findByPage(Integer pageNum, Integer pageSize) {

Integer count = userDao.findCount();

Integer index = (pageNum - 1) * pageSize;

List<User> data = userDao.findByPage(index, pageSize);

return new PageBean(count, data, pageNum, pageSize);

}

public ResultInfo addOrUpdateUser(User user) {

User u = userDao.findByUid(user.getUid());

try {

if (u == null) {

user.setPassword(Md5Utils.encodeByMd5("123456"));

userDao.save(user);

} else {

userDao.update(user);

}

return new ResultInfo(true);

}catch (Exception e){

return new ResultInfo(false);

}

}

public ResultInfo delUser(Integer id) {

userDao.delete(id);

return new ResultInfo(true);

}

3.7.4 管理员管理

功能描述:

超级管理员对管理员的管理,可以添加管理员,修改管理员信息,删除管理员等。

图3-26?管理员管理页图

图3-27?管理员管理修改页图

Controller层

@RequestMapping(value = "/data/getAdmin",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getAdmin(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return adminService.findByPage(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setAdmin",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setAdmin(Admin admin)

{

????if(isSuper()) {

????????return adminService.addOrUpdate(admin);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delAdmin",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delAdmin(Integer id)

{

????if(isSuper()) {

????????return adminService.delete(id);

????}

????return new ResultInfo(false,"没有操作权限!");

}

前端

layui.use('table', function(){

??var table = layui.table;

??table.on('tool(demo)', function(obj){

????var data = obj.data;

?if(obj.event === 'del'){

??????layer.confirm('真的要删除吗?', function(index){

????????$.post('${pageContext.request.contextPath}/data/delAdmin?id='+data.id, {}, function(str){

???????? if(str.code === 0)

???????? {

???????? obj.del();

???????? layer.alert("删除成功");

???????? }else(str.code === 1);

???????? {

???????? layer.alert(str.msg);

???????? }

???????? });

????????layer.close(index);

??????});

????} else if(obj.event === 'edit'){

????????layer.open({

?????? ??type: 2,

?????? ??title:'修改管理员',

?????? ??area: ['350px', '300px'],

?????? ??content: 'AdminForm.jsp?type=1&id='+data.id+'&username='+data.username+'&password='+data.password+'&quanxian='+data.quanxian

?????? });

????}

??});

??

??var $ = layui.$, active = {

????addAdmin: function(){ //获取选中数据

???? layer.open({

???????? ??type: 2,

???????? ??title:'添加管理员',

???????? area: ['350px', '300px'],

???????? ??content: 'AdminForm.jsp'

???????? });

????}

??};

3.7.5 商家管理

功能描述:

管理员管理已在商城入驻的商家,可以修改商家的全部信息,删除商家等

图3-28?商家管理页图

图3-29?商家管理修改页图

Controller层

@RequestMapping(value = "/data/getShop",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getShop(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return shopsService.listShop(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setShop",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setShop(Shop shop)

{

????if(check()) {

????????return shopsService.addOrUpdate(shop);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delShop",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delShop(Integer id)

{

????if(check()) {

????????return shopsService.delete(id);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/ShopForm")

public String shopForm(Integer id)

{

????if(check()) {

????????Shop shop = shopsService.findShopsBySid(id);

????????request.setAttribute("Shop",shop);

????????return "/admin/page/ShopForm.jsp";

????}

????return null;

}

Service层

public PageBean listShop(Integer pageNum, Integer pageSize)

{

Integer total = shopsDao.findShopCount();

Integer index = (pageNum - 1) * pageSize;

List<Shop> list = shopsDao.findShopByPage(index, pageSize);

return new PageBean(total, list, pageNum, pageSize);

}

public Shop findShopsBySid(Integer sid) {

return shopsDao.findBySid(sid);

}

3.7.6 商铺管理

功能描述:

管理员对商铺的管理,包括正在出租的商铺和已经营业的商铺。可以添加新商铺,修改商铺,删除商铺。

图3-30?商铺管理页图

图3-31?商铺管理修改页图

Controller层

@RequestMapping(value = "/data/getRent",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getRent(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return shopsService.listRent(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setRent",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setRent(Shop shop)

{

????if(check()) {

????????return shopsService.addOrUpdate(shop);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delRent",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delRent(Integer id)

{

????if(check()) {

????????return shopsService.delete(id);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/RentForm")

public String rentForm(Integer id)

{

????if(check()) {

????????Shop shop = shopsService.findShopsBySid(id);

????????request.setAttribute("Shop",shop);

????????return "/admin/page/RentForm.jsp";

????}

????return null;

}

前端

layui.use('table', function(){

??var table = layui.table;

??table.on('tool(demo)', function(obj){

????var data = obj.data;

????if(obj.event === 'del'){

??????layer.confirm('真的要删除吗?', function(index){

????????$.post('${pageContext.request.contextPath}/data/delRent?id='+data.sid, {}, function(str){

???????? if(str.code === 0)

???????? {

???????? obj.del();

???????? layer.alert("删除成功");

???????? }else if(str.code === 1)

???????? {

???????? layer.alert("找不到数据,删除失败");

???????? }else if(str.code === 2)

???????? {

???????? layer.alert("权限不足,删除失败");

???????? }

???????? });

????????layer.close(index);

??????});

????} else if(obj.event === 'edit'){

????????layer.open({

?????? ??type: 2,

?????? ??title:'修改商铺',

??????????area: ['100%', '100%'],

?????? ??content: '${pageContext.request.contextPath}/data/RentForm?id='+data.sid

?????? });

????}

??});

3.7.7 合同管理

功能描述:

管理员对已经签订的合同的管理,可以查看合同,也可以删除合同。

图3-32?合同管理页图

图3-33?合同查看页图

Controller层

@RequestMapping(value = "/data/getCont",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getCont(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return contractService.findByPage(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setCont",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setCont(Contract contract)

{

????if(check()) {

????????return contractService.addOrUpdate(contract);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delCont",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delCont(String id)

{

????if(check()) {

????????return contractService.delete(id);

????}

????return new ResultInfo(false,"没有操作权限!");

} ?

3.7.8 首页轮播图管理

功能描述:

对网站首页轮播图的管理,可以添加和修改,删除轮播图,并且能够管理轮播图指向的链接,若指向链接为空,则不使用链接。可以选择上传本地的图片,也可以使用网络图片。

图3-34?首页轮播图管理页图

图3-35?首页轮播图修改页图

Controller层

@RequestMapping(value = "/data/getBanner",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getBanner(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return bannerService.findByPage(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setBanner",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setBanner(Banner banner)

{

????if(check()) {

????????return bannerService.addOrUpdate(banner);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delBanner",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delBanner(Integer id)

{

????if(check()) {

????????return bannerService.delete(id);

????}

????return new ResultInfo(false,"没有操作权限!");

}

3.7.9 活动和公告管理

功能描述:

对商城活动和公告的管理,可以发布活动和公告招商等信息,信息将展示在首页显眼的位置。管理员可以添加新的活动和公告,修改活动和公告,删除活动和公告。

图3-36?公告和活动管理页图

图3-37?公告和活动修改页图

Controller层

@RequestMapping(value = "/data/getAnno",produces = "application/json;charset=utf-8")

@ResponseBody

public PageBean getAnno(@RequestParam(defaultValue = "1")Integer page, @RequestParam(defaultValue = "10")Integer limit)

{

????if(check()) {

????????return announcementService.findByPage(page, limit);

????}

????return null;

}

@RequestMapping(value = "/data/setAnno",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo setAnno(Announcement announcement)

{

????if(check()) {

????????return announcementService.addOrUpdate(announcement);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/delAnno",produces = "application/json;charset=utf-8")

@ResponseBody

public ResultInfo delAnno(Integer id)

{

????if(check()) {

????????return announcementService.delete(id);

????}

????return new ResultInfo(false,"没有操作权限!");

}

@RequestMapping(value = "/data/AnnoForm")

public String annoForm(Integer id)

{

????if(check()) {

????????Announcement announcement = announcementService.findById(id);

????????request.setAttribute("Anno",announcement);

????????return "/admin/page/AnnoForm.jsp";

????}

????return null;

}

3.8?事务管理

3.8.1 声明式事务

事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。Spring中的事务分为编程式事务和声明式事务,本系统使用的是声明式事务,Spring也推荐使用声明式事务。声明式事务是将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。通过在xml文件中写一段配置实现,在需要使用事务时在指定方法或者类中添加@Transactional注解即可,方法执行之前启动事务,遇到运行时错误时自动回滚,没有遇到错误则提交事务。

XML配置

<aop:aspectj-autoproxy expose-proxy="true" />

<tx:annotation-driven transaction-manager="txManager" />

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

????<property name="dataSource" ref="dataSource" />

</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">

????<tx:attributes>

????????<tx:method name="save*" propagation="REQUIRED" />

????????<tx:method name="add*" propagation="REQUIRED" />

????????<tx:method name="update*" propagation="REQUIRED" />

????????<tx:method name="del*" propagation="REQUIRED" />

????????<tx:method name="reg*" propagation="REQUIRED" />

????????<tx:method name="*" read-only="true" />

????</tx:attributes>

</tx:advice>

<aop:config expose-proxy="true">

????<aop:pointcut id="txPointcut"

??????????????????expression="execution(* com.qiang.mall.service.*.*(..))" />

????<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />

</aop:config>

4 系统测试

4.1 测试用例

用例编号

操作描述

预期结果

测试结果

1

启动系统进入登录界面,不输入任何信息

提示“用户名不能为空”信息

提示“用户名不能为空”信息

2

输入用户名,不输入密码,点击登录按钮

提示“密码不能为空”信息

提示“密码不能为空”信息

3

输入密码,不输入用户名,点击登录按钮

提示“用户名不能为空”信息

提示“用户名不能为空”信息

4

输入用户名和密码,点击登录按钮

提示“请输入验证码”

提示“请输入验证码”

5

输入用户名和密码,错误的验证码,点击登录按钮

提示“验证码错误”

提示“验证码错误”

6

输入用户名和密码,正确的验证码,点击登录按钮

登录成功并跳转至系统主页

登录成功并跳转至系统主页

4-1 ?用户账号登录测试用例

用例编号

操作描述

预期结果

测试结果

1

启动系统进入登录界面,不输入任何信息

提示“手机号不能为空”信息

提示“手机号不能为空”信息

2

输入手机号,不输入验证码,点击登录按钮

提示“验证码不能为空”信息

提示“验证码不能为空”信息

3

输入手机号,输入错误验证码,点击登录按钮

提示“验证码错误”信息

提示“验证码错误”信息

4

输入手机号,输入正确验证码,点击登录按钮

登录成功并跳转至系统主页

登录成功并跳转至系统主页

4-2??用户手机登录测试用例

4.2 功能测试

测试内容

测试结果

入驻商家列表查看,商家详情页查看

通过

入驻商家留言评论评分

通过

租赁商铺列表查看,商铺详情页查看

通过

手写签字,在线签订租赁合同

通过

在线微信支付

通过

聊天大厅聊天

通过

管理员后台管理用户信息

通过

管理员后台管理入驻商家信息

通过

管理员后台管理租赁商铺信息

通过

管理员后台管理租赁合同信息

通过

管理员后台审核合同,审核过期商铺信息

通过

管理员发布和管理商城公告和活动信息

通过

管理员管理首页轮播图信息

通过

4-3??功能测试


5 总结

至此,毕业设计全部完成,..........

源码下载地址:https://download.csdn.net/download/sunqiang4/21180240

打不开就是在审核

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-19 11:55:18  更:2021-08-19 11:56:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 2:46:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码