基于SSM实现软件测试管理系统
引言
Hello,大家好,本周博主为大家带来一个基于SSM的软件测试管理系统,系统分为两大模块,用户与bug模块其中管理员管理用户,为用户分配角色,分为开发或测试,用户管理bug模块,其中,测试提交bug,写好bug信息,进行提交,开发人员对bug进行修改,直至测试确认bug修改完成后,结束对话。
文字表达难免表达不清楚,下面看效果图
效果图时长3分钟,要耐心看下去哦
效果图
技术栈
- 后端:==Java、Spring、Spring MVC、 MyBatis==
- 前端:bootstrap、jsp
软件测试管理系统
系统支持防跳墙,利用Spring MVC Interceptor拦截器实现,
实体类采用lombok插件
系统采用三层架构完成
数据表准备
t_user用户表
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`userpwd` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`realname` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`usertype` int(11) DEFAULT NULL COMMENT '账号类型,1:开发,2:测试',
PRIMARY KEY (`id`)
)
t_bug_topic bug主题表
CREATE TABLE `t_bug_topic` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bug_title` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'bug主题',
`bug_detail` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'bug详细信息',
`bug_level` int(11) DEFAULT NULL COMMENT 'bug级别:1:功能优化、2:一般异常、3:重大异常',
`test_user_id` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '测试用户id',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '当前日期',
`bug_status` int(11) DEFAULT '0' COMMENT '当前bug状态,1 未处理 2 修改完成待确认 3 修改被驳回 4 修改完成已确认',
PRIMARY KEY (`id`)
)
t_bug_trace bug跟踪表
CREATE TABLE `t_bug_trace` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`topic_id` int(11) DEFAULT NULL COMMENT 'bugid',
`send_user_id` int(11) DEFAULT NULL COMMENT '发送人员id',
`send_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '当前日期',
`detail_info` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '详细信息',
`bug_status` int(11) DEFAULT NULL COMMENT '当前状态:0 普通沟通 2 修改完成,提交确认 3 修改驳回 4 修改完成已确认',
PRIMARY KEY (`id`)
)
项目结构
Java源码
配置文件
前端结构
搭建项目
pom依赖文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>APPTestManagerSystem</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- mybatis依赖的坐标 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!-- java连接mysql的驱动坐标 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
核心源码
bean层
User用户类
package com.wanshi.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TUser {
private Integer id;
private String username;
private String userpwd;
private String realname;
private Integer usertype;
}
BugTopic Bug主题类
package com.wanshi.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BugTopic {
private Integer id;
private String bug_title;
private String bug_detail;
private Integer bug_level;
private Integer test_user_id;
private Date create_time;
private Integer bug_status;
private String testUsername;
private String createTime;
}
BugTrace Bug跟踪类
package com.wanshi.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BugTrace {
private Integer id;
private Integer topic_id;
private Integer send_user_id;
private Date send_time;
private String detail_info;
private Integer bug_status;
private String sendUserName;
private String sendTime;
private String userType;
}
Page 分页类
package com.wanshi.bean;
import java.util.ArrayList;
import java.util.List;
/**
* 分页类,使用该类需传入3个参数,
* currPage:当前页数
* pageSize:每页显示的记录数
* rowCount:总共的记录数
*
* 注意::初始化该类后,使用该类的currPageFirstRowIndex属性传入数据访问层进行分页
* 分页完成后返回list集合,需要将返回的list集合通过该类的setList方法存入数据即可完成
*
* @author 王会称
*
* @param <T>
*/
public class Page<T> {
/**
* 当前页前面的页数
*/
private static final int BeforePageNumbCount = 4;
/**
* 当前页后面的页数
*/
private static final int AfterPageNumbCount = 3;
/**
* 当前页
*/
private int currPage;
/**
* 总记录数
*/
private int rowCount;
/**
* 分页的第二个参数,用于展示每页显示几条数据
* limit arg1, arg2 arg2
*
*/
private int pageSize;
/**
* 总页数
*/
private int pageCount;
/**
* 前一页
*/
private int prevPageNumb;
/**
* 后一页
*/
private int nextPageNumb;
/**
* 从第几条开始截取,分页的第一个参数
* limit arg1, arg2 arg1
*
*/
private int currPageFirstRowIndex;
/**
* 当前页的集合
*/
private List<T> list;
/**
* 当前显示的按钮数,前4后3
*/
private List<Integer> pageButtonNumbs ;
/**
* 初始化分页类,传入当前页,每页的记录数,总记录数
* @param _currPage
* @param _pageSize
* @param _rowCount
*/
public Page(int _currPage, int _pageSize, int _rowCount){
//初始化固定数据,每页的数据记录数,总记录数
this.pageSize = _pageSize;
this.rowCount = _rowCount;
// 计算出当前共有多少页
this.pageCount = this.rowCount / this.pageSize;
if(this.rowCount% this.pageSize !=0 ){
this.pageCount ++ ;
}
// 修正当前页
this.currPage = _currPage ;
if(this.currPage< 1 ){
this.currPage = 1;
}
if(this.currPage > this.pageCount ){
this.currPage = this.pageCount;
}
// 计算limit分页的第一个参数
this.currPageFirstRowIndex = (this.currPage-1)* this.pageSize ;
//如果小于0,那就从0开始截取
if (this.currPageFirstRowIndex < 0) {
this.currPageFirstRowIndex = 0;
}
// 计算前一页与后一页
this.prevPageNumb = this.currPage - 1;
this.nextPageNumb = this.currPage + 1;
//修正前一页
if(this.prevPageNumb<1){
this.prevPageNumb = 1;
}
//修正后一页
if(this.nextPageNumb >1 && this.nextPageNumb > this.pageCount){
this.nextPageNumb = this.pageCount;
}
// 计算当前的按钮数
this.pageButtonNumbs = new ArrayList();
for( int i = this.currPage - BeforePageNumbCount ; i <= this.currPage+AfterPageNumbCount ;i++){
if(i<1 || i> this.pageCount ){
continue;
}
this.pageButtonNumbs.add(i);
}
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
public int getCurrPage() {
return currPage;
}
public int getRowCount() {
return rowCount;
}
public int getPageSize() {
return pageSize;
}
public int getPageCount() {
return pageCount;
}
public int getPrevPageNumb() {
return prevPageNumb;
}
public int getNextPageNumb() {
return nextPageNumb;
}
public List<Integer> getPageButtonNumbs() {
return pageButtonNumbs;
}
public int getCurrPageFirstRowIndex() {
return currPageFirstRowIndex;
}
@Override
public String toString() {
return "Page [currPage=" + currPage + ", rowCount=" + rowCount + ", pageSize=" + pageSize + ", pageCount="
+ pageCount + ", prevPageNumb=" + prevPageNumb + ", nextPageNumb=" + nextPageNumb
+ ", currPageFirstRowIndex=" + currPageFirstRowIndex + ", list=" + list + ", pageButtonNumbs="
+ pageButtonNumbs + "]";
}
}
controller层
RouteController 路由跳转类,用于携带数据跳转到指定jsp页面进行渲染
package com.wanshi.controller;
import com.wanshi.bean.BugTopic;
import com.wanshi.bean.TUser;
import com.wanshi.service.BugTopicService;
import com.wanshi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/route")
public class RouteController {
@Autowired
private UserService userService;
@Autowired
private BugTopicService bugTopicService;
@GetMapping("/index")
public String index() {
return "index";
}
@GetMapping("/addUser")
public String userAdd() {
return "user/add";
}
@GetMapping("/updateUser")
public String updateUser(String id, Model model) {
TUser tUser = userService.get(Integer.valueOf(id));
model.addAttribute("user", tUser);
return "user/edit";
}
@GetMapping("/addBug")
public String addBug() {
return "bug/add";
}
@GetMapping("/updateBug")
public String updateBug(String id, Model model) {
BugTopic bugTopic = bugTopicService.get(Integer.valueOf(id));
model.addAttribute("bug", bugTopic);
return "bug/edit";
}
@GetMapping("/disposeBug")
public String disposeBug(String id, HttpServletRequest request) {
BugTopic bugTopic = bugTopicService.get(Integer.valueOf(id));
request.getSession().setAttribute("bug", bugTopic);
return "redirect:/bug_trace/list";
}
}
BugTopicController bug主题控制器类
package com.wanshi.controller;
import com.wanshi.bean.BugTopic;
import com.wanshi.bean.Page;
import com.wanshi.service.BugTopicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
@RequestMapping("/bug_topic")
public class BugTopicController {
@Autowired
private BugTopicService bugTopicService;
private static final Integer PageSize = 2;
@GetMapping("/page")
public String page(HttpServletRequest request, Model model) {
String bugTitle = request.getParameter("bug_title");
String bugLevel = request.getParameter("bug_level");
String testUsername = request.getParameter("test_username");
String pageNumb = request.getParameter("pageNumb");
Integer currPage = 1;
if (pageNumb != null && !pageNumb.equals("")) {
currPage = Integer.valueOf(pageNumb);
}
Page<BugTopic> page = bugTopicService.page(bugTitle, bugLevel, testUsername, currPage, PageSize);
model.addAttribute("pager", page);
model.addAttribute("bugTitle", bugTitle);
model.addAttribute("bugLevel", bugLevel);
model.addAttribute("testUsername", testUsername);
return "bug/list";
}
@PostMapping("/addHandle")
public String addHandle(BugTopic bugTopic) {
bugTopicService.insert(bugTopic);
return "redirect:/bug_topic/page";
}
@PostMapping("/editHandle")
public String editHandle(BugTopic bugTopic) {
System.out.println(bugTopic);
bugTopicService.update(bugTopic);
return "redirect:/bug_topic/page";
}
}
service层
BugTopicService
package com.wanshi.service;
import com.wanshi.bean.BugTopic;
import com.wanshi.bean.Page;
import java.util.List;
public interface BugTopicService {
Page<BugTopic> page(String bugTitle, String bugLevel, String testUsername, Integer currPage, Integer pageSize);
void update(BugTopic bugTopic);
void insert(BugTopic bugTopic);
BugTopic get(Integer id);
}
BugServiceImpl 实现类
package com.wanshi.service.impl;
import com.wanshi.bean.BugTopic;
import com.wanshi.bean.Page;
import com.wanshi.mapper.BugTopicMapper;
import com.wanshi.service.BugTopicService;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BugTopicServiceImpl implements BugTopicService {
private BugTopicMapper bugTopicMapper;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public void setBugTopicMapper(BugTopicMapper bugTopicMapper) {
this.bugTopicMapper = bugTopicMapper;
}
public Page<BugTopic> page(String bugTitle, String bugLevel, String testUsername, Integer currPage, Integer pageSize) {
Map<String, Object> maps = new HashMap<String, Object>();
maps.put("bugTitle", bugTitle);
maps.put("bugLevel", bugLevel);
maps.put("testUsername", testUsername);
Integer rowCount = bugTopicMapper.getTotal(maps);
Page<BugTopic> page = new Page<BugTopic>(currPage, pageSize, rowCount);
maps.put("currPage", page.getCurrPageFirstRowIndex());
maps.put("pageSize", pageSize);
List<BugTopic> bugTopicList = bugTopicMapper.page(maps);
for (BugTopic bugTopic : bugTopicList) {
bugTopic.setCreateTime(sdf.format(bugTopic.getCreate_time()));
}
page.setList(bugTopicList);
return page;
}
public void update(BugTopic bugTopic) {
bugTopicMapper.update(bugTopic);
}
public void insert(BugTopic bugTopic) {
bugTopicMapper.insert(bugTopic);
}
public BugTopic get(Integer id) {
BugTopic bugTopic = bugTopicMapper.get(id);
bugTopic.setCreateTime(sdf.format(bugTopic.getCreate_time()));
return bugTopic;
}
}
mapper层
BugTopicMapper
package com.wanshi.mapper;
import com.wanshi.bean.BugTopic;
import java.util.List;
import java.util.Map;
public interface BugTopicMapper {
List<BugTopic> page(Map<String, Object> maps);
void update(BugTopic bugTopic);
void insert(BugTopic bugTopic);
BugTopic get(Integer id);
Integer getTotal(Map<String, Object> maps);
}
BugTopicMapper.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="com.wanshi.mapper.BugTopicMapper">
<select id="page" resultType="com.wanshi.bean.BugTopic">
SELECT bug.*, user.`realname` testUsername FROM t_bug_topic bug JOIN t_user1105 USER ON user.id = bug.test_user_id
<where>
<if test="bugTitle != null and bugTitle != ''">
bug_title like concat('%',#{bugTitle},'%')
</if>
<if test="bugLevel != null and bugLevel != ''">
and bug_level = #{bugLevel}
</if>
<if test="testUsername != null and testUsername != ''">
and test_user_id = (SELECT u.`id` FROM t_user1105 u WHERE realname LIKE concat('%',#{testUsername},'%'))
</if>
</where>
limit #{currPage}, #{pageSize}
</select>
<insert id="insert">
insert into t_bug_topic (bug_title, bug_detail, bug_level,test_user_id)
values (#{bug_title}, #{bug_detail}, #{bug_level}, #{test_user_id})
</insert>
<update id="update">
update t_bug_topic
<set>
<if test="bug_title != null and bug_title != ''">bug_title = #{bug_title},</if>
<if test="bug_detail != null and bug_detail != ''">bug_detail = #{bug_detail},</if>
<if test="bug_level != null and bug_level != ''">bug_level = #{bug_level},</if>
<if test="test_user_id != null and test_user_id != ''">test_user_id = #{test_user_id},</if>
<if test="bug_status != null and bug_status != ''">bug_status = #{bug_status},</if>
create_time = now()
</set>
where id = #{id}
</update>
<select id="get" resultType="com.wanshi.bean.BugTopic">
SELECT bug.*, user.`realname` testUsername FROM t_bug_topic bug JOIN t_user1105 USER ON user.id = bug.test_user_id where bug.`id` = #{id}
</select>
<select id="getTotal" resultType="int">
select count(*) from t_bug_topic
<where>
<if test="bugTitle != null and bugTitle != ''">
bug_title like concat('%',#{bugTitle},'%')
</if>
<if test="bugLevel != null and bugLevel != ''">
and bug_level = #{bugLevel}
</if>
<if test="testUsername != null and testUsername != ''">
and test_user_id = (SELECT u.`id` FROM t_user1105 u WHERE realname LIKE concat('%',#{testUsername},'%'))
</if>
</where>
</select>
</mapper>
项目源码就分享到此,由于文件太多,本博客只介绍核心类,若对本项目感兴趣的老铁,可在下方链接获取完整项目
结语
本博客到此结束,系统还是有些逻辑性的,建议多练习,巩固知识,提示自己的逻辑思维能力
完整项目链接:基于SSM框架软件测试管理系统
提取码: jg3f
有任何问题均可在评论区留言或私信我
只求您能留下您宝贵的足迹,等啥呢,都看到这啦,还不来个一键三连嘛(==收藏+关注+评论==)
感谢您的支持,我们下篇见~