一、前情提要
各位朋友新年快乐,今天是年初八,由于春节的关系,【机房报修管理系统】
停更了一段时间,但是并不是弃坑了,我会再以后尽量1~2天一更,把前端篇和后端篇的坑填上。
上一次我们做完了管理员的Controller层的开发,这一次我们进行工单管理的开发;由于在上一篇文章《【机房报修管理系统】 后端篇(十九) Controller层开发——管理员相关接口》对一些简单的增删改查的接口有详细的说明,所以接下来的Controller开发中,对于一些比较简单的接口就不再赘述,请各位同学自行查看上面提到的文章。
二、接口功能设想
在工单管理接口中,除了最基本的增删改查的功能外,还需要有一个受理工单
和完成工单
功能,用于管理员在后台能够对工单进行改变工单状态。在保存工单
,即报修人在报修的时候,可以提供上传图片功能。
受理工单
时,工单状态从未受理
转为受理中
,工单需要填上受理的管理员编号,并且发送邮件给报修人留下的邮箱,和报修人说明工单正在维修中。
完成工单
时,首先将工单在数据库表Order
(未受理或受理中工单)转存到CompleteOrder
(已完成工单),并且删除Order
表中的相应数据,相应的机房可用电脑数+1。
三、接口设计以及实现
注意:以下的接口不再进行详细说明,需要的同学请查看我的GitHub
getAllOrdersInfo
(获得所有维修工单信息)getOrdersInfoById
(通过维修工单ID获得工单信息)updateOrders
(修改维修工单)deleteOrders
(删除维修工单)
前期准备
在pom.xml
中导入相应的第三方工具
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
设定存储图片的虚拟目录以及文件上传配置
在application.properties
中编写以下配置
# 文件上传配置
spring.servlet.multipart.max-file-size=100Mb
spring.servlet.multipart.max-request-size=1000Mb
#维修工单图片虚拟目录
order.img.dir=/opt/Image
#所有的访问都经过静态资源路径
spring.mvc.static-path-pattern=/**
#配置静态资源路径
spring.resources.static-locations= \
classpath:/META-INF/resources/,\
classpath:/resources/,\
classpath:/static/,\
classpath:/public/,\
file:${order.img.dir}
1.创建一个工单管理相关的类OrderController
在com.repairsystem.web.controller
下常见工单管理类OrderController
@RestController
@Api(value = "维修工单相关接口", tags = {"维修工单业务相关接口"})
@RequestMapping("/orders")
public class OrderController {
@Autowired
private OrdersService ordersService;
@Autowired
private ClassService classService;
@Autowired
private CompleteOrderService completeOrderService;
@Autowired
private EmailService emailService;
}
2.创建工单的VO类OrderVO
在com.repairsystem.entity.vo
下创建VO类OrderVO
下面的@JsonFormat
注解是用于在以JSON格式输出的时候规定输出的格式
package com.repairsystem.entity.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
/**
* @author CheungChingYin
* @date 2018/11/2
* @time 21:40
*/
public class OrderVO {
private Integer orderId;
private String problem;
private Integer computerNumber;
private String className;
private String buildingName;
private Integer status;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date submitTime;
private String imagesPath;
private Integer adminId;
private String adminName;
private String userName;
private String userPhone;
private String userEmail;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public String getProblem() {
return problem;
}
public void setProblem(String problem) {
this.problem = problem;
}
public Integer getComputerNumber() {
return computerNumber;
}
public void setComputerNumber(Integer computerNumber) {
this.computerNumber = computerNumber;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getBuildingName() {
return buildingName;
}
public void setBuildingName(String buildingName) {
this.buildingName = buildingName;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getSubmitTime() {
return submitTime;
}
public void setSubmitTime(Date submitTime) {
this.submitTime = submitTime;
}
public String getImagesPath() {
return imagesPath;
}
public void setImagesPath(String imagesPath) {
this.imagesPath = imagesPath;
}
public String getAdminName() {
return adminName;
}
public void setAdminName(String adminName) {
this.adminName = adminName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPhone() {
return userPhone;
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public Integer getAdminId() {
return adminId;
}
public void setAdminId(Integer adminId) {
this.adminId = adminId;
}
@Override
public String toString() {
return "OrderVO{" +
"orderId=" + orderId +
", problem='" + problem + '\'' +
", computerNumber=" + computerNumber +
", className='" + className + '\'' +
", buildingName='" + buildingName + '\'' +
", status=" + status +
", submitTime=" + submitTime +
", imagesPath='" + imagesPath + '\'' +
", adminId=" + adminId +
", adminName='" + adminName + '\'' +
", userName='" + userName + '\'' +
", userPhone='" + userPhone + '\'' +
", userEmail='" + userEmail + '\'' +
'}';
}
}
3.实现上传图片功能:uploadImage
-
URI:
/orders/uploadImage
-
请求方式:
POST
-
参数:
file
(属于多文件类MultipartFile
) -
返回信息:状态码200,图片路径信息(上传图片成功时)
-
返回信息:状态码500,存储图片时出现的异常(上传图片失败时)
-
返回信息:Null(没有图片上传时)
-
接口实现方法:
1.检查上传的file是否为空,为空则返回null
2.调用图片上传工具
3.如果返回的map有success
则视为上传成功,返回图片的上传地址。
4.如果返回的map为空或者出success
外的其他key值,则返回上传图片出现的异常。 -
上传图片工具类
OrderUploadUtils
的实现方法
1.检查传入的file是否为空,如果为空则返回map提示为空。
2.以yyyy-MM-dd
的格式获取当前日期。
3.存储的文件夹地址以固定的前缀地址/当前日期/
,检查有没有此文件夹存在,如果不存在则创建相应的文件夹。
4.检查文件的格式是否属于gif,jpg,jpeg,png
,如果不属于则返回错误信息说明文件格式不对。
5.文件以文件名当前时间+UUID.jpg
的格式储存,如果储存失败则返回失败信息,储存成功则返回图片存储路径。
虚拟目录的地址(按照上面配置的虚拟目录地址进行填写)
在com.repairsystem.utils.ConstantUtils
编写以下常量
class Path {
//虚拟目录地址
public static final String DIRPATH = "/opt/Image";
}
在com.repairsystem.utils
创建图片上传工具OrderUploadUtils
package com.repairsystem.utils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author CheungChingYin
* @date 2018/11/13
* @time 10:40
*/
@Component
public class OrderUploadUtils {
private static String dir = ConstantUtils.Path.DIRPATH;
public static Map<String, String> upLoadOrderImage(MultipartFile file) {
Map<String, String> resultMap = new HashMap<String, String>();
if (file.isEmpty()) {
resultMap.put("failure", "传入的文件为空");
return resultMap;
}
SimpleDateFormat simpleDateFormatDate = new SimpleDateFormat("yyyy-MM-dd");
String currentDate = simpleDateFormatDate.format(new Date());
String fileName = file.getOriginalFilename();
String realPath = dir + "/" + currentDate + "/";
File fileDir = new File(realPath);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
String extName = FilenameUtils.getExtension(fileName);
String allowImgFormat = "gif,jpg,jpeg,png";
if (!allowImgFormat.contains(extName.toLowerCase())) {
resultMap.put("failure", "传入的文件不是图像");
return resultMap;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd&HH-mm-ss");
String currentTime = simpleDateFormat.format(new Date());
fileName = currentTime + UUID.randomUUID() + ".jpg";
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
try {
inputStream = file.getInputStream();
fileOutputStream = new FileOutputStream(realPath + fileName);
IOUtils.copy(inputStream, fileOutputStream);
} catch (IOException e) {
resultMap.put("failure", "图片储存失败");
e.printStackTrace();
return resultMap;
} finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(fileOutputStream);
}
resultMap.put("success", "/" + currentDate + "/" + fileName);
return resultMap;
}
}
在com.repairsystem.web.controller.OrderController
编写接口逻辑
@ApiOperation(value = "上传工单图片")
@PostMapping(value = "/uploadImage")
public JsonResult uploadImage(@ApiParam(value = "图片上传") MultipartFile file){
if (!file.isEmpty()) {
String dbPath = null;
Map<String,String> map = OrderUploadUtils.upLoadOrderImage(file);
if (map.get("success") != null){
dbPath = map.get("success");
return JsonResult.ok(dbPath);
}else{
return JsonResult.errorMsg(map.get("failure"));
}
} else {
return null;
}
}
4.保存维修工单:saveOrders
- URI:
/orders/saveOrders
- 请求方式
POST
- 请求参数:problem(工单问题,数据类型为
String
) - 请求参数:computerNumber(电脑编号,数据类型为
Integer
) - 请求参数:classId(实训室ID,数据类型为
Integer
) - 请求参数:buildingId(实训楼ID,数据类型为
Integer
) - 请求参数:userName(报修人名字,数据类型为
String
) - 请求参数:userPhone(报修人手机号,数据类型为
String
) - 请求参数:userEmail(报修人邮箱,数据类型为
String
) - 请求参数:imagePath(图片路径,数据类型为
String
) - 返回信息:状态码200(成功时)
- 返回信息:状态码500(失败时)
- 实现方法:
1.创建一个order对象,将获得的信息存入对象中。
2.对象order的属性状态设置为0
(未受理)
3.对象order的提交时间setSubmitTime
设置为当前时间
4.将信息存入数据库中
5.调用reduceComputerEnable
方法将对应实训室的可用电脑减少1台。
@ApiOperation(value = "保存维修工单")
@ApiImplicitParams({
@ApiImplicitParam(name = "problem", value = "维修工单问题", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "computerNumber", value = "维修电脑编号", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "classId", value = "所属实训室编号", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "buildingId", value = "所属实训楼编号", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "userName", value = "报修人名称", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "userPhone", value = "报修人电话", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "userEmail", value = "报修人邮箱", required = true, dataType = "String", paramType = "form"),
@ApiImplicitParam(name = "imagePath", value = "图片地址", required = true, dataType = "String", paramType = "form"),
})
@PostMapping(value = "/saveOrders")
public JsonResult saveOrders(String problem, Integer computerNumber, Integer classId, Integer buildingId, String userName, String userPhone, String userEmail, String imagePath) {
if (StringUtils.isBlank(classId.toString())) {
JsonResult.errorMsg("传入的实训室ID(classId)不能为空");
}
Orders orders = new Orders();
orders.setImagesPath(imagePath);
orders.setProblem(problem);
orders.setComputerNumber(computerNumber);
orders.setClassId(classId);
orders.setBuildingId(buildingId);
orders.setStatus(0);//刚提交维修工单状态是未维修状态0
orders.setUserName(userName);
orders.setUserPhone(userPhone);
orders.setUserEmail(userEmail);
orders.setSubmitTime(new Date());
ordersService.saveOrder(orders);
classService.reduceComputerEnable(orders.getClassId());
return JsonResult.ok();
}
5.接受维修工单receiveOrder
- URI:
/orders/receiveOrder
- 请求方法:
GET
- 请求参数:orderId(维修工单ID,数据类型为
Integer
) - 请求参数:adminId(接受维修工单管理员ID,数据类型为
Integer
) - 返回信息:状态码200(成功时)
- 返回信息:状态码500,返回邮件发送失败信息(邮件发送失败时)
- 实现方法:
1.通过工单ID获得工单对象。
2.通过工单ID更新工单的接收管理员ID并且工单状态为1(受理中)。
3.调用邮件服务发送邮件
@ApiOperation(value = "接受维修工单")
@ApiImplicitParams({
@ApiImplicitParam(name = "orderId", value = "维修工单ID", required = true, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "adminId",value = "接受维修工单管理员ID",required = true,dataType = "String", paramType = "query"),
})
@GetMapping("/receiveOrder")
public JsonResult receiveOrder(Integer orderId, Integer adminId){
Orders orderInfo = ordersService.searchOrderById(orderId);
Orders order = new Orders();
order.setOrderId(orderId);
order.setAdminId(adminId);
order.setStatus(1);
ordersService.updateOrder(order);
String emailResult = emailService.acceptOrderMail(orderInfo.getUserName(),orderInfo.getUserEmail());
if(!"OK".equals(emailResult)){
JsonResult.errorMsg("邮件发送失败");
}
return JsonResult.ok();
}
6.完成维修工单orderComplete
- URI:
/orders/orderComplete
- 请求方法:
POST
- 请求参数:orderId(维修工单ID,数据类型为
Integer
) - 请求参数:remark(维修备注,数据类型为
String
) - 返回信息:状态码200(成功时)
- 返回信息:状态码500,返回邮件发送失败信息(邮件发送失败时)
- 实现方法:
1.通过工单ID获得工单对象信息。
2.将工单信息转存到completeOrder
对象中,并且存入completeOrder
数据表(工单完成表)中。
3.删除在`orders``数据表中的相应数据。
4.在相应的实训室可用电脑+1(维修完成)。
5.发送邮件到报修人的邮箱中,提示维修已完成。
@ApiOperation(value = "完成维修工单")
@ApiImplicitParams({
@ApiImplicitParam(name = "orderId", value = "维修工单ID", required = true, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "remark",value = "维修备注",dataType = "Long",paramType = "query")
})
@PostMapping("/orderComplete")
public JsonResult orderComplete(Integer orderId, String remark){
if (StringUtils.isBlank(orderId.toString())){
return JsonResult.errorMsg("传入的维修工单ID(orderId)不能为空");
}
Orders order = ordersService.searchOrderById(orderId);
CompleteOrder completeOrder = Entity2VO.entity2VO(order, CompleteOrder.class);
if(StringUtils.isNoneBlank(remark)){
completeOrder.setRemark(remark);
}
completeOrder.setImagePath(order.getImagesPath());
completeOrder.setCompleteTime(new Date());
completeOrder.setAdminName(null);
completeOrder.setClassName(null);
completeOrder.setBuildingName(null);
try {
completeOrderService.saveCompleteOrder(completeOrder);
} catch (Exception e) {
return JsonResult.errorException(e.getMessage());
}
ordersService.deleteOrder(orderId);
classService.increaseComputerEnable(order.getClassId());
String emailResult = emailService.completeOrderMail(order.getUserName(),order.getUserEmail());
if(!"OK".equals(emailResult)){
JsonResult.errorMsg("邮件发送失败");
}
return JsonResult.ok();
}
到这里,Controller层开发——工单管理相关接口已经开发完成了。如果您对次篇文章有疑问,可以在文章下方留言,谢谢您的阅读。如对【机房报修管理系统】系列文章有兴趣,可以关注或收藏我的文章,您的支持是我最大的动力,我会尽快推出下一期内容,敬请期待。