1. 前言
前一篇文章 图书管理系统实战(一) 中,我们已经编写了 pojo、dao 层以及配置 dao 层对应的 mapper,从现在开始,我们开始编写 service 层和 controller 层。
2. service 层
2.1 预约业务操作码
在正式编写 service 层之前,我们先定义一个预约图书操作返回码的数据字段,用于反馈给客户信息;
返回码 说明
1 预约成功
0 预约失败
-1 预约重复
-2 系统异常
package com.cunyu.utils; import com.cunyu.dto.AppointDto; import lombok.AllArgsConstructor; import lombok.Getter; /** * @author : cunyu * @version : 1.0 * @className : AppointStateEnum * @date : 2020/7/24 10:50 * @description : 定义预约业务的数据字典 */ @Getter @AllArgsConstructor public enum AppointStateEnum { SUCCESS(1, "预约成功"), FAILURE(0, "预约失败"), REPEAT(-1, "预约重复"), SYSTEMERROR(-2, "系统异常"); private int state; private String stateInfo; /** * @param stat 状态码 * @return * @description 获取状态码对应 enum * @date 2020/7/24 10:57 * @author cunyu1943 * @version 1.0 */ public static AppointStateEnum stateOf(int stat) { for (AppointStateEnum state : values() ) { if (stat == state.getState()) { return state; } } return null; } }
3.2 数据传输层
定义好预约业务的数据字典之后,新建一个数据传输类用来传输我们的预约结果;
package com.cunyu.dto; import com.cunyu.pojo.Appointment; import com.cunyu.utils.AppointStateEnum; import lombok.Data; import lombok.NoArgsConstructor; /** * @author : cunyu * @version : 1.0 * @className : AppointDto * @date : 2020/7/24 10:46 * @description : 用于数据传输,封装 */ @Data @NoArgsConstructor public class AppointDto { private int bookId; // 状态码 private int state; // 状态信息 private String stateInfo; // 预约成功的对象 private Appointment appointment; // 预约失败的构造器 public AppointDto(int bookId, AppointStateEnum appointStateEnum) { this.bookId = bookId; this.state = appointStateEnum.getState(); this.stateInfo = appointStateEnum.getStateInfo(); } // 预约成功的构造器 public AppointDto(int bookId, AppointStateEnum appointStateEnum, Appointment appointment) { this.bookId = bookId; this.state = appointStateEnum.getState(); this.stateInfo = appointStateEnum.getStateInfo(); this.appointment = appointment; } }
2.3 service 业务代码编写
2.3.1 BookService.java
package com.cunyu.service; import com.cunyu.dto.AppointDto; import com.cunyu.pojo.Book; import java.util.List; /** * @author : cunyu * @version : 1.0 * @className : BookService * @date : 2020/7/24 10:44 * @description : Book 业务接口 */ public interface BookService { /** * @param bookId 图书 ID * @return 对应 ID 的图书 * @description 根据图书 id 查询图书 * @date 2020/7/24 11:41 * @author cunyu1943 * @version 1.0 */ Book getById(int bookId); /** * @param * @return 所有图书的列表 * @description 获取图书列表 * @date 2020/7/24 11:41 * @author cunyu1943 * @version 1.0 */ List<Book> getList(); /** * @param bookId 图书 id * @param studentId 学生 Id * @return * @description 返回预约结果 * @date 2020/7/24 11:39 * @author cunyu1943 * @version 1.0 */ AppointDto appoint(int bookId, int studentId); }
2.3.2 BookServiceImpl.java
package com.cunyu.service.impl; import com.cunyu.dao.AppointmentDao; import com.cunyu.dao.BookDao; import com.cunyu.dto.AppointDto; import com.cunyu.pojo.Appointment; import com.cunyu.pojo.Book; import com.cunyu.service.BookService; import com.cunyu.utils.AppointStateEnum; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author : cunyu * @version : 1.0 * @className : BookServiceImpl * @date : 2020/7/24 11:43 * @description : Book 业务接口实现类 */ @Service public class BookServiceImpl implements BookService { // 依赖注入 @Autowired private BookDao bookDao; @Autowired private AppointmentDao appointmentDao; public Book getById(int bookId) { return bookDao.queryById(bookId); } public List<Book> getList() { return bookDao.queryAll(0, 3); } public AppointDto appoint(int bookId, int studentId) { AppointDto appointDto = null; try { // 减库存 int update = bookDao.reduceNumber(bookId); if (update <= 0) { System.out.println(AppointStateEnum.FAILURE); } else { // 执行预约操作 int insert = appointmentDao.insertAppointment(bookId, studentId); if (insert <= 0) { System.out.println(AppointStateEnum.REPEAT); } else { Appointment appointment = appointmentDao.queryByKeyWithBook(bookId, studentId); appointDto = new AppointDto(bookId, AppointStateEnum.SUCCESS, appointment); } } } catch (Exception e) { e.printStackTrace(); } return appointDto; } }
2.4 测试
package com.cunyu.service.impl; import com.cunyu.service.BookService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author : cunyu * @version : 1.0 * @className : BookServiceImplTest * @date : 2020/7/24 11:53 * @description : BookServiceImpl 测试类 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring/spring-*.xml") public class BookServiceImplTest { @Autowired private BookService bookService; @Test public void testAppoint() { int bookId = 1; int studentId = 18301343; System.out.println(bookService.appoint(bookId, studentId)); } }
下图是我们测试后数据库中的数据,说明此时我们的 service 层接口测试成功。
2.5 封装结果
既然我们的 service 层接口和实现类都编写好了,我们就需要将结果进行封装成 json 格式,方便我们传到 controller 交互使用。
package com.cunyu.dto; import lombok.Data; import lombok.NoArgsConstructor; /** * @author : cunyu * @version : 1.0 * @className : ResultDto * @date : 2020/7/24 12:11 * @description : 封装结果为 json */ @Data @NoArgsConstructor public class ResultDto<T> { // 是否预约成功 private boolean success; // 预约成功返回的数据 private T data; // 错误信息 private String error; // 预约成功的构造器 public ResultDto(boolean success, T data) { this.success = success; this.data = data; } // 预约失败的构造器 public ResultDto(boolean success, String error) { this.success = success; this.error = error; } }
3. controller 层
编写好 service 层之后,我们就剩下最后的 controller 层了;
package com.cunyu.controller; import com.cunyu.dto.AppointDto; import com.cunyu.dto.ResultDto; import com.cunyu.pojo.Book; import com.cunyu.service.BookService; import com.cunyu.utils.AppointStateEnum; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.List; /** * @author : cunyu * @version : 1.0 * @className : BookController * @date : 2020/7/24 12:20 * @description : Book controller 层 */ @Controller @RequestMapping("/book") public class BookController { @Autowired private BookService bookService; // url:ip:port:/book/list @GetMapping("/list") private String list(Model model) { List<Book> bookList = bookService.getList(); model.addAttribute("bookList", bookList); return "list"; } @GetMapping(value = "/{bookId}/detail") private String detail(@PathVariable("bookId") Integer bookId, Model model) { if (bookId == null) { return "redirect:/book/list"; } Book book = bookService.getById(bookId); if (book == null) { return "forward:/book/list"; } model.addAttribute("book", book); return "detail"; } //ajax 传递 json 数据到前端 @RequestMapping(value = "/{bookId}/appoint", method = RequestMethod.POST, produces = {"application/json; charset=utf-8"}) @ResponseBody private ResultDto<AppointDto> appoint(@PathVariable("bookId") Integer bookId, @RequestParam("studentId") Integer studentId) { if (studentId == null || studentId.equals("")) { return new ResultDto<>(false, "学号不能为空"); } AppointDto appointDto = null; try { appointDto = bookService.appoint(bookId, studentId); } catch (Exception e) { e.printStackTrace(); } return new ResultDto<AppointDto>(true, appointDto); } }
4. 前端
好了,我们的后台就开发完毕了,接下来就可以去编写前端页面了。然后启动 Tomcat,访问对应 url 即可。
4.1 list.jsp
<%-- Created by IntelliJ IDEA. User: cunyu Date: 2020/7/23 Time: 9:47 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>图书列表页</title> </head> <body> <h1>${bookList}</h1> </body> </html>
4.2 detail.jsp
<%-- Created by IntelliJ IDEA. User: cunyu Date: 2020/7/23 Time: 10:02 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>图书详情页</title> </head> <body> <h1>${book.name}</h1> <h2>${book.bookId}</h2> <h2>${book.number}</h2> </body> </html>
5. 总结
到此,我们的后台所有服务都写好了,SSM 框架整合配置,与应用实例部分已经结束,前端部分就简单写了个数据展示页面。