业务形容
基于 Spring,MyBatis,SpringBoot,Thymeleaf,Ajax 技术实现流动模块的查问, 增加等操作。
我的项目环境初始化
筹备工作
1. MySQL(5.7)
2. JDK (1.8)
3. Maven (3.6.3)
4. STS(4.7.1)
数据库初始化
关上 mysql 控制台, 而后按如下步骤执行 goods.sql 文件。
第一步: 登录 mysql。
mysql –uroot –proot
第二步: 设置控制台编码方式。
set names utf8;
第三步: 执行 activity.sql 文件(切记不要关上文件复制到 mysql 客户端运行)。
source d:/activity.sql
其中 activity.sql 文件内容如下:
drop database if exists dbactivity;
create database dbactivity default character set utf8;
use dbactivity;
create table tb_activity(
id bigint primary key auto_increment,
title varchar(100) not null,
category varchar(100) not null,
startTime datetime not null,
endTime datetime not null,
remark text,
state tinyint,
createdTime datetime not null,
createdUser varchar(100)
)engine=InnoDB;
insert into tb_activity values (null,'ABS','cuoxiao','2020-02-02 15:00:00','2020-02-03 15:00:00','...',1,now(),'xiaoli');
insert into tb_activity values (null,'VALIDATE','cuoxiao','2020-02-02 15:00:00','2020-02-03 15:00:00','...',1,now(),'xiaoli');
insert into tb_activity values (null,'VALIDATE','cuoxiao','2020-02-02 15:00:00','2020-02-03 15:00:00','...',1,now(),'xiaoli');
insert into tb_activity values (null,'ABS','cuoxiao','2020-02-02 15:00:00','2020-02-03 15:00:00','...',1,now(),'xiaoli');
insert into tb_activity values (null,'ACCESS','cuoxiao','2020-02-02 15:00:00','2020-02-03 15:00:00','...',1,now(),'xiaoli');
创立我的项目并增加依赖
第一步:基于 start.spring.io 创立我的项目并设置根本信息。
第二步:创立我的项目时指定我的项目外围依赖。
第三步:我的项目创立当前剖析其构造。
我的项目配置文件内容初始化
#server
server.port=80
#server.servlet.context-path=/
#spring datasource
spring.datasource.url=jdbc:mysql:///dbactivity?serverTimezone=GMT%2B8&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
#spring mybatis
mybatis.mapper-locations=classpath:/mapper/*/*.xml
#spring logging
logging.level.com.cy=debug
#spring thymeleaf
spring.thymeleaf.prefix=classpath:/templates/modules/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false
我的项目 API 架构设计
其 API 架构设计,如图所示:
流动模块查问业务实现
业务形容
从数据库查问所有流动 (Activity) 信息,而后出现在页面上(基于 JS 形式进行出现), 如图所示:
业务时序剖析
在浏览器地址栏输出查问流动信息的 url 获取流动信息,其时序过程如图所示:
POJO 类设计及实现
创立 Activity 类, 基于此类对象封装从数据库获取的流动信息, 代码如下:
package com.cy.pj.activity.pojo;
import java.util.Date;
import lombok.Data;
@Data
public class Activity {
private Integer id;
private String title;
private String category;
private Date startTime;
private Date endTime;
private String remark;
private Integer state;
private Date createdTime;
private String createdUser;
}
其中,@Data 注解为 Lombok 注解, 须要在 IDE 环境中曾经装置 lombok 插件, 我的项目中增加 lombok 依赖, 如果没有也能够本人增加 set/get 相干办法
Dao 接口办法及映射定义
定义流动模块数据层接口及查询方法,代码如下:
package com.cy.pj.activity.dao;
import com.cy.pj.activity.pojo.Activity;
@Mapper
public interface ActivityDao {@Select("select * from tb_activity order by createdTime desc")
List<Activity> findActivitys();}
Service 接口办法定义及实现
定义 service 接口以及获取流动信息的办法,代码如下:
package com.cy.pj.activity.service;
import java.util.List;
import com.cy.pj.activity.pojo.Activity;
// 引入包中的类:ctrl+shift+o
public interface ActivityService {List<Activity> findActivitys();
}
定义 service 接口实现类,并重写接口办法,代码如下:
package com.cy.pj.activity.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.cy.pj.activity.dao.ActivityDao;
import com.cy.pj.activity.pojo.Activity;
import com.cy.pj.activity.service.ActivityService;
@Service
public class ActivityServiceImpl implements ActivityService {
@Autowired
private ActivityDao activityDao;
@Override
public List<Activity> findActivitys() {return activityDao.findActivitys();
}
}
Controller 办法定义及实现
package com.cy.pj.activity.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.cy.pj.activity.pojo.Activity;
import com.cy.pj.activity.service.ActivityService;
@Controller
public class ActivityController {
@Autowired
private ActivityService activityService;
@RequestMapping("/activity/doActivityUI")
public String doActivityUI(){return "activity";}
/** 查问所有流动信息 */
@RequestMapping("/activity/doFindActivitys")
@ResponseBody
public List<Activity> doFindActivitys() {List<Activity> list=activityService.findActivitys();
return list;
}
}
Activity 列表页面设计及实现
本次页面款式基于 bootstrap(一个前端框架,官网为 bootcss.com)进行实现,首先在我的项目工程中增加动态资源,如图所示:
设计 activity.html 页面,引入 bootstrap,jquery 等相干资源,如图所示:
在 activity.html 页面中增加出现 Activity 数据的 html 元素:
<table class="table">
<thead>
<tr>
<th>title</th>
<th>Category</th>
<th>StartTime</th>
<th>EndTime</th>
<th>State</th>
<th>Operation</th>
</tr>
</thead>
<tbody id="tbodyId">
<tr><td colspan="6"> 数据正在加载中.......</td></tr>
</tbody>
</table>
基于 Ajax 异步加载服务端流动数据并进行部分刷新
<script type="text/javascript"> function doFindActivitys(){
var url="/activity/doFindActivitys"
// 启动 ajax 技术, 基于 GET 申请形式获取服务端 json 数据
//getJSON 函数默认会将服务端返回的 json 串转换为 js 对象
$.getJSON(url,function(result){var tBody=$("#tbodyId");
tBody.empty();// 清空原有 body 内容
for(var i=0;i<result.length;i++){// 循环一次, 迭代一行
// 构建以后行对象
var tr=`<tr>
<td>${result[i].title}</td>
<td>${result[i].category}</td>
<td>${result[i].startTime}</td>
<td>${result[i].endTime}</td>
<td>${result[i].state==1?'无效':'有效'}</td>
<td><button type='button' class='btn btn-danger btn-sm'>delete</button></td>
</tr>`
// 将每一行的内容都追加 tbody 中
tBody.append(tr);
}
});
};
doFindActivitys(); </script>
启动 tomcat 服务器进行拜访测试剖析
启动我的项目,在浏览器中输出 activity 页面的拜访地址,出现流动信息,如图所示:
客户端断点调试剖析, 如图所示:
运行时断点设置, 如图所示:
进入断点办法外部, 如图所示:
查看响应数据在客户端的出现, 如图所示:
我的项目启动及运行过程中的 BUG 剖析
- 数据库链接的 url 配置谬误,如图所示:
- 空指针异样,如图所示:
- JS 引入谬误,如图所示:
- JS 语法错误,如图所示:
流动模块增加业务实现
业务形容
在流动列表页面,设计增加按钮,点击增加按钮时弹出模态框,在模态框中出现流动增加表单元素,其增加表单原型设计,
如图所示:
业务时序剖析
流动增加业务,其时序剖析,如图所示:
Dao 接口办法及映射定义
在 ActivityDao 接口中增加长久化流动信息的办法,代码如下:
int insertObject(Activity activity);
在 ActivityMapper 映射文件中增加映射元素,代码如下:
<insert id="insertObject" parameterType="com.cy.pj.activity.pojo.Activity"
useGeneratedKeys="true" keyProperty="id">
insert into tb_activity
(title,category,startTime,endTime,remark,state,createdUser,createdTime)
values
(#{title},#{category},#{startTime},#{endTime},
#{remark},#{state},#{createdUser},now())
</insert>
“#{}” 表达式数据获取剖析, 如图所示:
执行 insert 操作时获取数据库主键 id 值,如图所示:
当然,也能够以注解的形式进行 SQL 映射,如图所示:当流动创立好当前,如果到了完结工夫,动静更新流动的状态,代码如下:
@Update("update tb_activity set state=0 where id=#{id}")
int updateState(Long id);
Service 接口办法定义及实现
在 ActivityService 接口中,增加保留流动信息的办法,代码如下:
int saveActivity(Activity entity);
在 ActivityServiceImpl 实现类中增加,接口办法的实现,代码如下:
@Override
public int saveActivity(Activity entity) {int rows=activityDao.insertObject(entity);
Timer timer=new Timer();
// 此对象能够负责去执行一些工作(这个对象内置一个线程和一个工作队列)
// 启动线程执行任务调度
timer.schedule(new TimerTask() {//TimerTask 为工作
@Override
public void run() {
// 一旦调用此工作的线程取得了 CPU 就会执行这个工作的 run 办法
activityDao.updateState(entity.getId());
timer.cancel();// 退出任务调度(后续线程也会销毁)
}
}, entity.getEndTime());// 按指定工夫执行工作.
return rows;
}
Controller 办法定义及实现
在 ActivityController 中增加,解决增加申请的办法,代码如下:
@RequestMapping("/activity/doSaveActivity")
@ResponseBody
public String doSaveActivity(Activity activity) {activityService.saveActivity(activity);
return "save ok";
}
Activity 页面增加表单设计及实现
在 activity.html 页面中增加表单元素,用于实现与用户交互,首先在 activity 页面上增加一个增加按钮,代码如下:
<button type="button" class="btn btn-primary btn-sm"
data-toggle="modal" data-target="#myModal"> 创建活动
</button>
在指定地位增加模态框(可参考 bootcss.com),代码如下:
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel"> 创建活动 </h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="doSaveObject()">
Save Changes</button>
</div>
</div>
</div>
</div>
在模态框”modal-body”地位,增加 form 表单,代码如下:
<form class="form-horizontal" th:action="@{/activity/doSaveActivity}" method="post">
<div class="form-group">
<label for="titleId" class="col-sm-2 control-label"> 题目 </label>
<div class="col-sm-10">
<input type="text" class="form-control" name="title" id="titleId" placeholder="title">
</div>
</div>
<div class="form-group">
<label for="categoryId" class="col-sm-2 control-label"> 类型 </label>
<div class="col-sm-10">
<select id="categoryId" name="category" class="form-control">
<option value="教育培训"> 教育培训 </option>
<option value="企业流动"> 企业流动 </option>
<option value="交友流动"> 交友流动 </option>
</select>
</div>
</div>
<div class="form-group" >
<label for="startTimeId" class="col-sm-2 control-label"> 开始工夫 </label>
<div class="col-sm-10">
<input type="text" class="form-control form_datetime"
name="startTime" id="startTimeId" placeholder="start time">
</div>
</div>
<div class="form-group">
<label for="endTimeId" class="col-sm-2 control-label"> 完结工夫 </label>
<div class="col-sm-10">
<input type="text" class="form-control form_datetime"
name="endTime" id="endTimeId" placeholder="end time">
</div>
</div>
<div class="form-group">
<label for="remarkId" class="col-sm-2 control-label"> 备注 </label>
<div class="col-sm-10">
<textarea type="text" class="form-control" rows="5" name="remark" id="remarkId">
</textarea>
</div>
</div>
</form>
增加 JS 代码,解决模态框 Save 按钮事件,代码如下:
function doSaveObject(){
//1. 定义 url
let url="/activity/doSaveObject";
//2. 定义申请参数
var params=
$("#saveFormId").serialize();//serialize()为 jquery 中间接获取表单数据办法
console.log("params",params);
//3. 发送异步申请
$.ajax({
type:"post",
url:url,
data:params,
success:function(result){alert(result);
// 暗藏模态框
$('#myModal').modal('hide');
// 从新执行查问,部分刷新
findActivitys();}
});
}
启动 tomcat 服务器进行拜访测试剖析
启动 tomcat,拜访流动列表页面,如图所示:
在流动列表页面,点击增加按钮,而后启动流动增加模块框,执行增加操作如图所示:
Spring MVC 为办法参数赋值剖析, 如图所示:
日历控件拓展实现(开始工夫和完结工夫通过抉择实现),成果展现,如图所示:
Bootstrap-datapicker 控件的实现过程,如图所示:
我的项目启动及运行过程中的 BUG 剖析
- BindingException,如图所示:
- 400 异样,如图所示:
- 服务端日期格局设计,如图所示:
- 完整性束缚异样, 如图所示:
总结(Summary)
本模块中解说了流动模块中类的设计,映射设计,交互设计以及实现,而后能够基于此模块的练习增强对业务和技术上的设计及是实现。