├── .gitignore ├── .settings ├── org.eclipse.wst.jsdt.ui.superType.name ├── org.eclipse.wst.validation.prefs ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.m2e.core.prefs ├── org.eclipse.wst.common.project.facet.core.xml ├── .jsdtscope ├── org.eclipse.wst.common.component └── org.eclipse.jdt.core.prefs ├── src └── main │ ├── webapp │ ├── index.jsp │ ├── WEB-INF │ │ ├── jsp │ │ │ ├── common │ │ │ │ ├── tag.jsp │ │ │ │ └── head.jsp │ │ │ ├── appointBookList.jsp │ │ │ ├── list.jsp │ │ │ └── detail.jsp │ │ └── web.xml │ └── resources │ │ └── script │ │ └── bookappointment.js │ ├── resources │ ├── jdbc.properties │ ├── mapper │ │ ├── StudentDao.xml │ │ ├── BookDao.xml │ │ └── AppointmentDao.xml │ ├── logback.xml │ ├── mybatis-config.xml │ └── spring │ │ ├── spring-service.xml │ │ ├── spring-web.xml │ │ └── spring-dao.xml │ ├── java │ └── com │ │ └── imooc │ │ └── appoint │ │ ├── exception │ │ ├── AppointException.java │ │ ├── NoNumberException.java │ │ └── RepeatAppointException.java │ │ ├── dao │ │ ├── StudentDao.java │ │ ├── BookDao.java │ │ └── AppointmentDao.java │ │ ├── entiy │ │ ├── Student.java │ │ ├── Book.java │ │ └── Appointment.java │ │ ├── enums │ │ └── AppointStateEnum.java │ │ ├── dto │ │ ├── Result.java │ │ └── AppointExecution.java │ │ ├── service │ │ ├── BookService.java │ │ └── Impl │ │ │ └── BookServiceImpl.java │ │ └── web │ │ └── BookController.java │ └── sql │ └── schema.sql ├── .project ├── .classpath ├── pom.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /src/main/resources/jdbc.properties: -------------------------------------------------------------------------------- 1 | jdbc.driver=com.mysql.jdbc.Driver 2 | jdbc.url=jdbc:mysql://127.0.0.1:3306/ssmbookappoint?useUnicode=true&characterEncoding=utf8 3 | jdbc.username= 4 | jdbc.password= -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/common/tag.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 3 | <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 4 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/exception/AppointException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.exception; 2 | //预约义务异常 3 | public class AppointException extends RuntimeException{ 4 | public AppointException(String message) { 5 | super(message); 6 | } 7 | 8 | public AppointException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/dao/StudentDao.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.dao; 2 | 3 | import org.apache.ibatis.annotations.Param; 4 | 5 | import com.imooc.appoint.entiy.Student; 6 | 7 | public interface StudentDao { 8 | /** 9 | * 向数据库验证输入的密码是否正确 10 | */ 11 | Student quaryStudent(@Param("studentId") long studentId, @Param("password") long password); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/exception/NoNumberException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.exception; 2 | 3 | //库存不足异常 4 | public class NoNumberException extends RuntimeException{ 5 | public NoNumberException(String message) { 6 | super(message); 7 | } 8 | 9 | public NoNumberException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/exception/RepeatAppointException.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.exception; 2 | //重复预约异常 3 | public class RepeatAppointException extends RuntimeException{ 4 | public RepeatAppointException(String message) { 5 | super(message); 6 | } 7 | 8 | public RepeatAppointException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/mapper/StudentDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/dao/BookDao.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.dao; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import com.imooc.appoint.entiy.Book; 8 | 9 | public interface BookDao { 10 | /* 11 | * 根据id查询书 12 | * 13 | */ 14 | Book queryById(long id); 15 | List querySome(String name); 16 | List queryAll(@Param("offset") int offset,@Param("limit") int limit); 17 | 18 | /*减少管存数量 19 | * 用返回值可判断当前库存是否还有书 20 | */ 21 | int reduceNumber(long bookId); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/dao/AppointmentDao.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.dao; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import com.imooc.appoint.entiy.Appointment; 8 | 9 | public interface AppointmentDao { 10 | //通过图书ID和学生ID预约书籍,并插入 11 | int insertAppointment(@Param("bookId") long bookId, @Param("studentId") long studentId); 12 | 13 | //通过一个学生ID查询已经预约了哪些书。 14 | List quaryAndReturn(long studentId); 15 | // //查询所有已经预约书籍,暂时不开发管理员界面 16 | // List queryAll(@Param("offset") int offset,@Param("limit") int limit); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/common/head.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/entiy/Student.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.entiy; 2 | 3 | public class Student { 4 | private Long studentId; 5 | private Long password; 6 | 7 | public Student(){ 8 | 9 | } 10 | public Student(Long studentId,Long password){ 11 | this.studentId=studentId; 12 | this.password=password; 13 | } 14 | public Long getStudentId() { 15 | return studentId; 16 | } 17 | public void setStudentId(Long studentId) { 18 | this.studentId = studentId; 19 | } 20 | public Long getPassword() { 21 | return password; 22 | } 23 | public void setPassword(Long password) { 24 | this.password = password; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "Student [studentId=" + studentId + ", password=" + password + "]"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.8 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 13 | org.eclipse.jdt.core.compiler.source=1.8 14 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | BookAppointment-dispatcher 7 | org.springframework.web.servlet.DispatcherServlet 8 | 9 | contextConfigLocation 10 | classpath:spring/spring-*.xml 11 | 12 | 13 | 14 | BookAppointment-dispatcher 15 | / 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/enums/AppointStateEnum.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.enums; 2 | 3 | //使用枚举表述常量数据字典,我们先定义几个预约图书操作返回码的数据字典,也就是我们要返回给客户端的信息。 4 | public enum AppointStateEnum { 5 | SUCCESS(1, "预约成功"), NO_NUMBER(0, "库存不足"), REPEAT_APPOINT(-1, "重复预约"), INNER_ERROR(-2, "系统异常"); 6 | 7 | private int state; 8 | 9 | private String stateInfo; 10 | 11 | private AppointStateEnum(int state, String stateInfo) { 12 | this.state = state; 13 | this.stateInfo = stateInfo; 14 | } 15 | 16 | public int getState() { 17 | return state; 18 | } 19 | 20 | public String getStateInfo() { 21 | return stateInfo; 22 | } 23 | 24 | public static AppointStateEnum stateOf(int index) { 25 | for (AppointStateEnum state : values()) { 26 | if (state.getState() == index) { 27 | return state; 28 | } 29 | } 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/dto/Result.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.dto; 2 | 3 | 4 | /** 5 | * 封装json对象,所有返回结果都使用它 6 | */ 7 | public class Result { 8 | private boolean success;// 是否成功标志 9 | 10 | private T data;// 成功时返回的数据 11 | 12 | private String error;// 错误信息 13 | 14 | public Result() { 15 | } 16 | 17 | // 成功时的构造器 18 | public Result(boolean success, T data) { 19 | this.success = success; 20 | this.data = data; 21 | } 22 | 23 | // 错误时的构造器 24 | public Result(boolean success, String error) { 25 | this.success = success; 26 | this.error = error; 27 | } 28 | 29 | 30 | public boolean isSuccess() { 31 | return success; 32 | } 33 | 34 | public void setSuccess(boolean success) { 35 | this.success = success; 36 | } 37 | 38 | public T getData() { 39 | return data; 40 | } 41 | 42 | public void setData(T data) { 43 | this.data = data; 44 | } 45 | 46 | public String getError() { 47 | return error; 48 | } 49 | 50 | public void setError(String error) { 51 | this.error = error; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/service/BookService.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.service; 2 | 3 | import java.util.List; 4 | 5 | import com.imooc.appoint.dto.AppointExecution; 6 | import com.imooc.appoint.entiy.Appointment; 7 | import com.imooc.appoint.entiy.Book; 8 | import com.imooc.appoint.entiy.Student; 9 | 10 | public interface BookService { 11 | /** 12 | * 查询一本图书 13 | * 14 | * @param bookId 15 | * @return 16 | */ 17 | Book getById(long bookId); 18 | /** 19 | * 查询所有图书 20 | * 21 | * @return 22 | */ 23 | List getList(); 24 | /** 25 | * 登陆时查询数据库是否有该学生记录。 26 | */ 27 | Student validateStu(Long studentId,Long password); 28 | /**按照图书名称查询 29 | * 按条件搜索图书 30 | * 31 | */ 32 | List getSomeList(String name); 33 | /* 34 | * 查看某学生预约的所有图书 35 | * 36 | */ 37 | List getAppointByStu(long studentId); 38 | /** 39 | * 预约图书 40 | * 41 | * @param bookId 42 | * @param studentId 43 | * @return 44 | */ 45 | AppointExecution appoint(long bookId, long studentId);//返回预约成功的实体类 46 | } 47 | -------------------------------------------------------------------------------- /src/main/resources/spring/spring-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/entiy/Book.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.entiy; 2 | 3 | public class Book { 4 | 5 | private long bookId;//图书ID 6 | private String name;//图书名称 7 | private int number;//馆藏数量 8 | private String introd; 9 | public Book() { //为什么要有个无参构造器 10 | } 11 | public Book(long bookId, String name, int number) { 12 | this.bookId = bookId; 13 | this.name = name; 14 | this.number = number; 15 | } 16 | public long getBookId() { 17 | return bookId; 18 | } 19 | public void setBookId(long bookId) { 20 | this.bookId = bookId; 21 | } 22 | public String getName() { 23 | return name; 24 | } 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | public int getNumber() { 29 | return number; 30 | } 31 | public void setNumber(int number) { 32 | this.number = number; 33 | } 34 | public String getIntrod() { 35 | return introd; 36 | } 37 | public void setIntrod(String introd) { 38 | this.introd = introd; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "Book [bookId=" + bookId + ", name=" + name + ", number=" + number + ", introd=" + introd + "]"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/dto/AppointExecution.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.dto; 2 | import com.imooc.appoint.enums.AppointStateEnum; 3 | 4 | public class AppointExecution { 5 | 6 | // 图书ID 7 | private long bookId; 8 | 9 | // 秒杀预约结果状态 10 | private int state; 11 | 12 | // 状态标识 13 | private String stateInfo; 14 | 15 | public AppointExecution() { 16 | } 17 | 18 | // 预约失败的构造器 19 | public AppointExecution(long bookId, AppointStateEnum stateEnum) { 20 | this.bookId = bookId; 21 | this.state = stateEnum.getState(); 22 | this.stateInfo = stateEnum.getStateInfo(); 23 | } 24 | 25 | //set get 方法! 26 | public long getBookId() { 27 | return bookId; 28 | } 29 | 30 | public void setBookId(long bookId) { 31 | this.bookId = bookId; 32 | } 33 | 34 | public int getState() { 35 | return state; 36 | } 37 | 38 | public void setState(int state) { 39 | this.state = state; 40 | } 41 | 42 | public String getStateInfo() { 43 | return stateInfo; 44 | } 45 | 46 | public void setStateInfo(String stateInfo) { 47 | this.stateInfo = stateInfo; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "AppointExecution [bookId=" + bookId + ", state=" + state + ", stateInfo=" + stateInfo+"]"; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/entiy/Appointment.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.entiy; 2 | 3 | import java.util.Date; 4 | 5 | public class Appointment { 6 | private long bookId; 7 | private long studentId; 8 | private Date appointTime; 9 | // 多对一的复合属性 10 | private Book book;// 图书实体 11 | public Appointment(){ 12 | } 13 | public Appointment(long bookId, long studentId, Date appointTime) { 14 | this.bookId = bookId; 15 | this.studentId = studentId; 16 | this.appointTime = appointTime; 17 | } 18 | public long getBookId() { 19 | return bookId; 20 | } 21 | public void setBookId(long bookId) { 22 | this.bookId = bookId; 23 | } 24 | public long getStudentId() { 25 | return studentId; 26 | } 27 | public void setStudentId(long studentId) { 28 | this.studentId = studentId; 29 | } 30 | public Date getAppointTime() { 31 | return appointTime; 32 | } 33 | public void setAppointTime(Date appointTime) { 34 | this.appointTime = appointTime; 35 | } 36 | public Book getBook() { 37 | return book; 38 | } 39 | public void setBook(Book book) { 40 | this.book = book; 41 | } 42 | @Override 43 | public String toString() { 44 | return "Appointment [bookId=" + bookId + ", studentId=" + studentId + ", appointTime=" + appointTime + ", book=" 45 | + book + "]"; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/mapper/BookDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 18 | 19 | 27 | 28 | 40 | 41 | 42 | UPDATE book 43 | SET number = number - 1 44 | WHERE 45 | book_id = #{bookId} 46 | AND number > 0 47 | 48 | 49 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ssm-BookAppointment 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | org.eclipse.wst.validation.validationbuilder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/spring/spring-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/mapper/AppointmentDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | INSERT ignore INTO appointment (book_id, student_id) 9 | VALUES (#{bookId}, #{studentId}) 10 | 11 | 14 | 15 | 32 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/appointBookList.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 2 | <%@include file="common/tag.jsp"%> 3 | 4 | 5 | 6 | 预约图书列表 7 | <%@include file="common/head.jsp" %> 8 | 9 | 10 |
11 |
12 |
13 |

您已预约图书列表

14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
预定学号预约时间图书ID图书名称图书简介预约数量
${sk.studentId}${sk.appointTime}${sk.bookId}${sk.book.getName()}${sk.book.getIntrod()}1
40 |
41 | 42 | 43 |
44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/sql/schema.sql: -------------------------------------------------------------------------------- 1 | -- 创建图书表 2 | CREATE TABLE `book` ( 3 | `book_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '图书ID', 4 | `name` varchar(100) NOT NULL COMMENT '图书名称', 5 | `introd` varchar(1000) NOT NULL COMMENT '简介', 6 | `number` int(11) NOT NULL COMMENT '馆藏数量', 7 | PRIMARY KEY (`book_id`) 8 | ) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='图书表'; 9 | 10 | -- 初始化图书数据 11 | INSERT INTO `book` (`book_id`, `name`, `introd`,`number`) 12 | VALUES 13 | (1000, 'Java程序设计', 'Java程序设计是一门balbal',10), 14 | (1001, '数据结构','数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。', 10), 15 | (1002, '设计模式','设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。',10), 16 | (1003, '编译原理','编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。',10), 17 | (1004,'大学语文','基于长期的教学实践和学科思考,我们编写了这本《大学语文》教材balbal',10), 18 | (1005,'计算方法','计算方法又称“数值分析”。是为各种数学问题的数值解答研究提供最有效的算法。',10), 19 | (1006,'高等数学','广义地说,初等数学之外的数学都是高等数学,也有将中学较深入的代数、几何以及简单的集合论初步balbal',10); 20 | 21 | -- 创建预约图书表 22 | CREATE TABLE `appointment` ( 23 | `book_id` bigint(20) NOT NULL COMMENT '图书ID', 24 | `student_id` bigint(20) NOT NULL COMMENT '学号', 25 | `appoint_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '预约时间' , 26 | PRIMARY KEY (`book_id`, `student_id`), 27 | INDEX `idx_appoint_time` (`appoint_time`) 28 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='预约图书表'; 29 | -- 创建学生数据表 30 | CREATE TABLE `student`( 31 | `student_id` bigint(20) NOT NULL COMMENT '学生ID', 32 | `password` bigint(20) NOT NULL COMMENT '密码', 33 | PRIMARY KEY(`student_id`) 34 | )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生统计表'; 35 | -- 初始化学生数据 36 | INSERT INTO `student`(`student_id`,`password`) 37 | VALUES 38 | (3211200801,346543), 39 | (3211200802,754323), 40 | (3211200803,674554), 41 | (3211200804,542344), 42 | (3211200805,298383), 43 | (3211200806,873973), 44 | (3211200807,193737), 45 | (3211200808,873092); 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/main/resources/spring/spring-dao.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/list.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 2 | <%@include file="common/tag.jsp"%> 3 | 4 | 5 | 6 | 图书列表 7 | <%@include file="common/head.jsp" %> 8 | 9 | 10 |
11 |
12 |
13 |

图书列表

14 |
15 |
16 |
17 | 18 | 19 | 20 | 21 | 24 | 27 | 28 | 29 |
图书名称: 22 | 23 | 25 | 26 |
30 |
31 |
32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
图书ID图书名称馆藏数量详细
${sk.bookId}${sk.name}${sk.number}详细
55 |
56 | 57 | 58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/service/Impl/BookServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.service.Impl; 2 | 3 | import java.util.List; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import com.imooc.appoint.dao.AppointmentDao; 12 | import com.imooc.appoint.dao.BookDao; 13 | import com.imooc.appoint.dao.StudentDao; 14 | import com.imooc.appoint.dto.AppointExecution; 15 | import com.imooc.appoint.entiy.Appointment; 16 | import com.imooc.appoint.entiy.Book; 17 | import com.imooc.appoint.entiy.Student; 18 | import com.imooc.appoint.enums.AppointStateEnum; 19 | import com.imooc.appoint.exception.AppointException; 20 | import com.imooc.appoint.exception.NoNumberException; 21 | import com.imooc.appoint.exception.RepeatAppointException; 22 | import com.imooc.appoint.service.BookService; 23 | 24 | @Service 25 | public class BookServiceImpl implements BookService{ 26 | private Logger logger=LoggerFactory.getLogger(this.getClass()); 27 | @Autowired 28 | private BookDao bookDao; 29 | @Autowired 30 | private AppointmentDao appointmentDao; 31 | @Autowired 32 | private StudentDao studentDao; 33 | @Override 34 | public Book getById(long bookId) { 35 | return bookDao.queryById(bookId); 36 | } 37 | @Override 38 | public List getList() { 39 | return bookDao.queryAll(0, 1000); 40 | } 41 | @Override 42 | public Student validateStu(Long studentId,Long password){ 43 | return studentDao.quaryStudent(studentId, password); 44 | } 45 | @Override 46 | public List getSomeList(String name) { 47 | 48 | return bookDao.querySome(name); 49 | } 50 | @Override 51 | public List getAppointByStu(long studentId) {//DOTO 52 | return appointmentDao.quaryAndReturn(studentId); 53 | 54 | } 55 | @Override 56 | @Transactional 57 | public AppointExecution appoint(long bookId, long studentId) {//在Dao的基础上组织逻辑,形成与web成交互用的方法 58 | try{ //返回成功预约的类型。 59 | int update=bookDao.reduceNumber(bookId);//减库存 60 | if(update<=0){//已经无库存! 61 | throw new NoNumberException("no number"); 62 | }else{ 63 | //执行预约操作 64 | int insert=appointmentDao.insertAppointment(bookId, studentId); 65 | if(insert<=0){//重复预约 66 | throw new RepeatAppointException("repeat appoint"); 67 | }else{//预约成功 68 | return new AppointExecution(bookId,AppointStateEnum.SUCCESS); 69 | } 70 | 71 | } 72 | } catch (NoNumberException e1) { 73 | throw e1; 74 | } catch (RepeatAppointException e2) { 75 | throw e2; 76 | } catch (Exception e) { 77 | logger.error(e.getMessage(), e); 78 | // 所有编译期异常转换为运行期异常 79 | throw new AppointException("appoint inner error:" + e.getMessage()); 80 | } 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/jsp/detail.jsp: -------------------------------------------------------------------------------- 1 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 2 | <%@include file="common/tag.jsp" %> 3 | 4 | 5 | 6 | 预约详情页 7 | <%@include file="common/head.jsp" %> 8 | 9 | 10 |
11 |
12 |
13 |

图书详情

14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
图书ID图书名称图书简介剩余数量预约数量
${book.bookId}${book.name}${book.introd}${book.number }1
36 |
37 |
38 |

39 | 40 | 41 | 42 | 查看我的已预约书籍 43 |

44 |
45 |
46 | 47 |
48 | 49 | 82 | 83 | 84 | <%--jQery文件,务必在bootstrap.min.js之前引入--%> 85 | 86 | 87 | <%--使用CDN 获取公共js http://www.bootcdn.cn/--%> 88 | <%--jQuery Cookie操作插件--%> 89 | 90 | <%--jQuery countDown倒计时插件--%> 91 | 92 | 93 | 94 | 95 | 104 | 105 | -------------------------------------------------------------------------------- /src/main/webapp/resources/script/bookappointment.js: -------------------------------------------------------------------------------- 1 | var bookappointment={ 2 | //封装相关ajax的url 3 | URL:{ 4 | appoint:function(bookId,studentId){ 5 | return '/books/'+bookId+'/appoint?studentId='+studentId; 6 | }, 7 | verify:function(){ 8 | return '/books'+'/verify'; 9 | } 10 | }, 11 | 12 | //验证学号和密码 13 | validateStudent:function(studentId,password){ 14 | console.log("studentId"+studentId); 15 | if(!studentId||!password){ 16 | return "nothing"; 17 | }else if(studentId.length!=10 ||isNaN(studentId)||password.length!=6 ||isNaN(password)){ 18 | return "typerror"; 19 | }else { 20 | if(bookappointment.verifyWithDatabase(studentId, password)){ 21 | console.log("验证成功!"); 22 | return "success"; 23 | }else{ 24 | console.log("验证失败!"); 25 | return "mismatch"; 26 | } 27 | } 28 | }, 29 | //将学号和用户名与数据库匹配 30 | verifyWithDatabase:function(studentId,password){ 31 | var result=false; 32 | var params={}; 33 | params.studentId=studentId; 34 | params.password=password; 35 | console.log("params.password:"+params.password); 36 | var verifyUrl=bookappointment.URL.verify(); 37 | $.ajax({ 38 | type:'post', 39 | url:verifyUrl, 40 | data:params, 41 | datatype:'josn', 42 | async:false, //同步调用,保证先执行result=true,后再执行return result; 43 | success:function(data){ 44 | if(data.result=='SUCCESS'){ 45 | window.location.reload(); 46 | //弹出登录成功! 47 | alert("登陆成功!"); 48 | result=true; 49 | }else{ 50 | result=false; 51 | } 52 | } 53 | }); 54 | console.log("我是验证结果:"+result); 55 | return result; 56 | 57 | }, 58 | 59 | //预定图书逻辑 60 | detail:{ 61 | //预定也初始化 62 | init:function(params){ 63 | var bookId=params['bookId']; 64 | console.log("我是js文件!"); 65 | 66 | var studentId=$.cookie('studentId'); 67 | var password=$.cookie('password'); 68 | if(!studentId||!password){ 69 | //设置弹出层属性 70 | var IdAndPasswordModal=$('#varifyModal'); 71 | IdAndPasswordModal.modal({ 72 | show: true,//显示弹出层 73 | backdrop: 'static',//禁止位置关闭 74 | keyboard: false//关闭键盘事件 75 | }); 76 | $('#studentBtn').click(function (){ 77 | studentId=$('#studentIdKey').val(); 78 | console.log("studentId:"+studentId); 79 | password=$('#passwordKey').val(); 80 | console.log("password:"+password); 81 | //调用validateStudent函数验证用户id和密码。 82 | var temp=bookappointment.validateStudent(studentId,password); 83 | console.log(temp); 84 | if(temp=="nothing"){ 85 | $('#studentMessage').hide().html('').show(300); 86 | }else if(temp=="typerror"){ 87 | $('#studentMessage').hide().html('').show(300); 88 | }else if(temp=="mismatch"){ 89 | console.log("已经调用验证函数!"); 90 | $('#studentMessage').hide().html('').show(300); 91 | }else if(temp=="success"){ 92 | //学号与密码匹配正确,将学号密码保存在cookie中。不设置cookie过期时间,这样即为session模式,关闭浏览器就不保存密码了。 93 | $.cookie('studentId', studentId, { path: '/books'}); 94 | $.cookie('password', password, { path: '/books'}); 95 | // 跳转到预约逻辑 96 | var appointbox=$('#appoint-box'); 97 | bookappointment.appointment(bookId,studentId,appointbox); 98 | } 99 | }); 100 | }else{ 101 | var appointbox=$('#appoint-box'); 102 | bookappointment.appointment(bookId,studentId,appointbox); 103 | } 104 | } 105 | }, 106 | appointment:function(bookId,studentId, node){ 107 | console.log("我执行预约的方法!" ); 108 | node.html(''); 109 | 110 | var appointmentUrl = bookappointment.URL.appoint(bookId,studentId); 111 | console.log("appointmentUrl:"+appointmentUrl); 112 | //绑定一次点击事件 113 | $('#appointmentBtn').one('click', function () { 114 | //执行预约请求 115 | //1、先禁用请求 116 | $(this).addClass('disabled'); 117 | //2、发送预约请求执行预约 118 | $.post(appointmentUrl,{},function(result){ //Ajax强大之处,向Controller方法提出请求和返回结果在一处! 119 | if(result && result['success']){ //同时还可以连续取对象的子对象! 120 | var appointResult=result['data']; 121 | console.log("appointResult"+appointResult); 122 | var state=appointResult['state']; 123 | console.log("state"+state); 124 | var stateInfo=appointResult['stateInfo']; 125 | console.log("stateInfo"+stateInfo); 126 | //显示预约结果 把结果显示给页面,完成了jsp的工作 127 | 128 | node.html(''+stateInfo+''); 129 | } //因为公用一个node所以,用来显示“stateInfo”时就不会显示上面的“预约” 130 | console.log('result'+result); 131 | }); 132 | }); 133 | 134 | 135 | } 136 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | cn.nize 5 | ssm-BookAppointment 6 | 1.0-SNAPSHOT 7 | ssm-BookAppointment Maven Webapp 8 | http://maven.apache.org 9 | 10 | 11 | 12 | 13 | junit 14 | junit 15 | 4.11 16 | 17 | 18 | 19 | 20 | 21 | ch.qos.logback 22 | logback-classic 23 | 1.1.1 24 | 25 | 26 | 27 | 28 | mysql 29 | mysql-connector-java 30 | 5.1.35 31 | 32 | 33 | 34 | c3p0 35 | c3p0 36 | 0.9.1.2 37 | 38 | 39 | 40 | 41 | org.mybatis 42 | mybatis 43 | 3.3.0 44 | 45 | 46 | org.mybatis 47 | mybatis-spring 48 | 1.2.3 49 | 50 | 51 | 52 | 53 | taglibs 54 | standard 55 | 1.1.2 56 | 57 | 58 | jstl 59 | jstl 60 | 1.2 61 | 62 | 63 | com.fasterxml.jackson.core 64 | jackson-databind 65 | 2.5.0 66 | 67 | 68 | com.fasterxml.jackson.core 69 | jackson-core 70 | 2.5.0 71 | 72 | 73 | com.fasterxml.jackson.core 74 | jackson-annotations 75 | 2.5.0 76 | 77 | 82 | 83 | javax.servlet 84 | javax.servlet-api 85 | 3.1.0 86 | 87 | 88 | 89 | 90 | 91 | org.springframework 92 | spring-core 93 | 4.1.7.RELEASE 94 | 95 | 96 | org.springframework 97 | spring-beans 98 | 4.1.7.RELEASE 99 | 100 | 101 | org.springframework 102 | spring-context 103 | 4.1.7.RELEASE 104 | 105 | 106 | 107 | org.springframework 108 | spring-jdbc 109 | 4.1.7.RELEASE 110 | 111 | 112 | org.springframework 113 | spring-tx 114 | 4.1.7.RELEASE 115 | 116 | 117 | 118 | org.springframework 119 | spring-web 120 | 4.1.7.RELEASE 121 | 122 | 123 | org.springframework 124 | spring-webmvc 125 | 4.1.7.RELEASE 126 | 127 | 128 | 129 | org.springframework 130 | spring-test 131 | 4.1.7.RELEASE 132 | 133 | 134 | 135 | 136 | redis.clients 137 | jedis 138 | 2.7.3 139 | 140 | 141 | com.dyuproject.protostuff 142 | protostuff-core 143 | 1.0.8 144 | 145 | 146 | com.dyuproject.protostuff 147 | protostuff-runtime 148 | 1.0.8 149 | 150 | 151 | 152 | 153 | commons-collections 154 | commons-collections 155 | 3.2 156 | 157 | 158 | 159 | 160 | ssm-BookAppointment 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/main/java/com/imooc/appoint/web/BookController.java: -------------------------------------------------------------------------------- 1 | package com.imooc.appoint.web; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | import org.apache.ibatis.annotations.Param; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Controller; 18 | import org.springframework.ui.Model; 19 | import org.springframework.web.bind.annotation.PathVariable; 20 | import org.springframework.web.bind.annotation.RequestMapping; 21 | import org.springframework.web.bind.annotation.RequestMethod; 22 | import org.springframework.web.bind.annotation.RequestParam; 23 | import org.springframework.web.bind.annotation.ResponseBody; 24 | 25 | import com.imooc.appoint.dto.AppointExecution; 26 | import com.imooc.appoint.dto.Result; 27 | import com.imooc.appoint.entiy.Appointment; 28 | import com.imooc.appoint.entiy.Book; 29 | import com.imooc.appoint.entiy.Student; 30 | import com.imooc.appoint.enums.AppointStateEnum; 31 | import com.imooc.appoint.service.BookService; 32 | import com.imooc.appoint.exception.RepeatAppointException; 33 | import com.imooc.appoint.exception.NoNumberException; 34 | 35 | 36 | @Controller 37 | @RequestMapping("/books") 38 | public class BookController { 39 | private Logger logger=LoggerFactory.getLogger(this.getClass()); 40 | @Autowired 41 | private BookService bookService; 42 | //获取图书列表 43 | @RequestMapping(value="/list",method = RequestMethod.GET) 44 | private String List(Model model){ 45 | List list = bookService.getList(); 46 | model.addAttribute("list", list); 47 | 48 | return "list"; 49 | } 50 | //搜索是否有某图书 51 | @RequestMapping(value="/search",method = RequestMethod.POST) 52 | private void search(HttpServletRequest req,HttpServletResponse resp) 53 | throws ServletException, IOException{ 54 | //接收页面的值 55 | String name=req.getParameter("name"); 56 | name=name.trim(); 57 | //向页面传值 58 | req.setAttribute("name", name); 59 | req.setAttribute("list", bookService.getSomeList(name)); 60 | req.getRequestDispatcher("/WEB-INF/jsp/list.jsp").forward(req, resp); 61 | } 62 | //查看某图书的详细情况 63 | @RequestMapping(value = "/{bookId}/detail", method = RequestMethod.GET) 64 | private String detail(@PathVariable("bookId") Long bookId, Model model){ 65 | if(bookId==null){ 66 | return "redict:/book/list"; 67 | } 68 | Book book=bookService.getById(bookId); 69 | if(book==null){ 70 | return "forward:/book/list"; 71 | } 72 | model.addAttribute("book",book); 73 | System.out.println(book); 74 | return "detail"; 75 | } 76 | //验证输入的用户名、密码是否正确 77 | @RequestMapping(value="/verify", method = RequestMethod.POST, produces = { 78 | "application/json; charset=utf-8" }) 79 | @ResponseBody 80 | private Map validate(Long studentId,Long password){ //(HttpServletRequest req,HttpServletResponse resp){ 81 | Map resultMap=new HashMap(); 82 | Student student =null; 83 | System.out.println("验证函数"); 84 | student =bookService.validateStu(studentId,password); 85 | 86 | System.out.println("输入的学号、密码:"+studentId+":"+password); 87 | System.out.println("查询到的:"+student.getStudentId()+":"+student.getPassword()); 88 | 89 | if(student!=null){ 90 | System.out.println("SUCCESS"); 91 | resultMap.put("result", "SUCCESS"); 92 | return resultMap; 93 | }else{ 94 | resultMap.put("result", "FAILED"); 95 | return resultMap; 96 | } 97 | 98 | } 99 | //执行预约的逻辑 100 | @RequestMapping(value = "/{bookId}/appoint", method = RequestMethod.POST, produces = { 101 | "application/json; charset=utf-8" }) 102 | @ResponseBody 103 | private Result execute(@PathVariable("bookId") Long bookId,@RequestParam("studentId") Long studentId){ 104 | Result result; 105 | AppointExecution execution=null; 106 | 107 | try{//手动try catch,在调用appoint方法时可能报错 108 | execution=bookService.appoint(bookId, studentId); 109 | result=new Result(true,execution); 110 | return result; 111 | 112 | } catch(NoNumberException e1) { 113 | execution=new AppointExecution(bookId,AppointStateEnum.NO_NUMBER); 114 | result=new Result(true,execution); 115 | return result; 116 | }catch(RepeatAppointException e2){ 117 | execution=new AppointExecution(bookId,AppointStateEnum.REPEAT_APPOINT); 118 | result=new Result(true,execution); 119 | return result; 120 | }catch (Exception e){ 121 | execution=new AppointExecution(bookId,AppointStateEnum.INNER_ERROR); 122 | result=new Result(true,execution); 123 | return result; 124 | } 125 | } 126 | @RequestMapping(value ="/appoint") 127 | private String appointBooks(@RequestParam("studentId") long studentId,Model model){ 128 | 129 | List appointList=new ArrayList(); 130 | appointList=bookService.getAppointByStu(studentId); 131 | model.addAttribute("appointList", appointList); 132 | 133 | return "appointBookList"; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ssm-BookAppointment
2 | 优雅整合SSM框架:SpringMVC + Spring + MyBatis(图书预约系统)
3 | 话不多说先让我们看看此项目运行起来的效果,方便大家有个直观了解,好在事先估计要用到那些技术,方便大家有针对性的学习。
4 | 看图!
5 | 这是图书管理系统的首页,不用登陆即可查看、搜索系统有已有图书。
6 | ![image](https://github.com/nize1989/pic/blob/master/raw/1.png) 7 | 搜索想要预定的书:
8 | ![image](https://github.com/nize1989/pic/blob/master/raw/2.png) 9 | 点击详情,进入预定页面,如果没有登陆的话会弹出登陆层,提示输入学号密码,如果用户已经在之前查看某本书的详细时已经登陆,则不会要求再登陆,这里的用户名密码与数据库验证成功后保存在cookie中,且生命周期默认与session相同,即关闭路径窗口后就失效。
10 | ![image](https://github.com/nize1989/pic/blob/master/raw/3.png) 11 | 这是什么都不输入和输入格式不对时,点击submit的提示:
12 | ![image](https://github.com/nize1989/pic/blob/master/raw/4.png) 13 | ![image](https://github.com/nize1989/pic/blob/master/raw/5.png) 14 | ![image](https://github.com/nize1989/pic/blob/master/raw/6.png) 15 | 登陆后进入预约界面,点击预约后的界面:
16 | ![image](https://github.com/nize1989/pic/blob/master/raw/7.png) 17 | 如果已经对当前书预约过,点击预约会提示重复预约,如果没有库存,点击预约会提示没有库存。
18 | ![image](https://github.com/nize1989/pic/blob/master/raw/8.png) 19 | 预约后点击:查看我的已预约书籍,会显示之前所有预约的信息:
20 | ![image](https://github.com/nize1989/pic/blob/master/raw/9.png) 21 | ## 1、利用maven创建文件路径:
22 | 利用命令行工具输入:mvn archetype:generate -DgroupId=cn.nize -DarchetypeArtifactId= 23 | maven-archetype-webapp -DarchetypeCatalog=internal
24 | ## 2、创建项目包:
25 | ![image](https://github.com/nize1989/pic/blob/master/raw/11.png) 26 | ## 3、再然后就是在pom.xml里面注入依赖,maven会自动在网站上下载。关于maven大家可以看看慕课网上的教学视频。 27 | pom.xml 28 | ```java 29 | 31 | 4.0.0 32 | cn.nize 33 | ssm-BookAppointment 34 | 1.0-SNAPSHOT 35 | ssm-BookAppointment Maven Webapp 36 | http://maven.apache.org 37 | 38 | 39 | 40 | 41 | junit 42 | junit 43 | 4.11 44 | 45 | 46 | 47 | 48 | 49 | ch.qos.logback 50 | logback-classic 51 | 1.1.1 52 | 53 | 54 | 55 | 56 | mysql 57 | mysql-connector-java 58 | 5.1.35 59 | 60 | 61 | 62 | c3p0 63 | c3p0 64 | 0.9.1.2 65 | 66 | 67 | 68 | 69 | org.mybatis 70 | mybatis 71 | 3.3.0 72 | 73 | 74 | org.mybatis 75 | mybatis-spring 76 | 1.2.3 77 | 78 | 79 | 80 | 81 | taglibs 82 | standard 83 | 1.1.2 84 | 85 | 86 | jstl 87 | jstl 88 | 1.2 89 | 90 | 91 | com.fasterxml.jackson.core 92 | jackson-databind 93 | 2.5.0 94 | 95 | 96 | com.fasterxml.jackson.core 97 | jackson-core 98 | 2.5.0 99 | 100 | 101 | com.fasterxml.jackson.core 102 | jackson-annotations 103 | 2.5.0 104 | 105 | 110 | 111 | javax.servlet 112 | javax.servlet-api 113 | 3.1.0 114 | 115 | 116 | 117 | 118 | 119 | org.springframework 120 | spring-core 121 | 4.1.7.RELEASE 122 | 123 | 124 | org.springframework 125 | spring-beans 126 | 4.1.7.RELEASE 127 | 128 | 129 | org.springframework 130 | spring-context 131 | 4.1.7.RELEASE 132 | 133 | 134 | 135 | org.springframework 136 | spring-jdbc 137 | 4.1.7.RELEASE 138 | 139 | 140 | org.springframework 141 | spring-tx 142 | 4.1.7.RELEASE 143 | 144 | 145 | 146 | org.springframework 147 | spring-web 148 | 4.1.7.RELEASE 149 | 150 | 151 | org.springframework 152 | spring-webmvc 153 | 4.1.7.RELEASE 154 | 155 | 156 | 157 | org.springframework 158 | spring-test 159 | 4.1.7.RELEASE 160 | 161 | 162 | 163 | 164 | redis.clients 165 | jedis 166 | 2.7.3 167 | 168 | 169 | com.dyuproject.protostuff 170 | protostuff-core 171 | 1.0.8 172 | 173 | 174 | com.dyuproject.protostuff 175 | protostuff-runtime 176 | 1.0.8 177 | 178 | 179 | 180 | 181 | commons-collections 182 | commons-collections 183 | 3.2 184 | 185 | 186 | 187 | 188 | ssm-BookAppointment 189 | 190 | 191 | ``` 192 | ## 4、做好之前的准备工作后,逻辑理顺,现在就要开始编码啦,首先我们创建数据库!
193 | 根据我们的实际情况,在数据库中创建表:
194 | schema.sql 195 | ```java 196 | -- 创建图书表 197 | CREATE TABLE `book` ( 198 | `book_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '图书ID', 199 | `name` varchar(100) NOT NULL COMMENT '图书名称', 200 | `introd` varchar(1000) NOT NULL COMMENT '简介', 201 | `number` int(11) NOT NULL COMMENT '馆藏数量', 202 | PRIMARY KEY (`book_id`) 203 | ) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='图书表'; 204 | 205 | -- 初始化图书数据 206 | INSERT INTO `book` (`book_id`, `name`, `introd`,`number`) 207 | VALUES 208 | (1000, 'Java程序设计', 'Java程序设计是一门balbal',10), 209 | (1001, '数据结构','数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。', 10), 210 | (1002, '设计模式','设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。',10), 211 | (1003, '编译原理','编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。',10), 212 | (1004,'大学语文','基于长期的教学实践和学科思考,我们编写了这本《大学语文》教材balbal',10), 213 | (1005,'计算方法','计算方法又称“数值分析”。是为各种数学问题的数值解答研究提供最有效的算法。',10), 214 | (1006,'高等数学','广义地说,初等数学之外的数学都是高等数学,也有将中学较深入的代数、几何以及简单的集合论初步balbal',10); 215 | 216 | -- 创建预约图书表 217 | CREATE TABLE `appointment` ( 218 | `book_id` bigint(20) NOT NULL COMMENT '图书ID', 219 | `student_id` bigint(20) NOT NULL COMMENT '学号', 220 | `appoint_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '预约时间' , 221 | PRIMARY KEY (`book_id`, `student_id`), 222 | INDEX `idx_appoint_time` (`appoint_time`) 223 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='预约图书表'; 224 | -- 创建学生数据表 225 | CREATE TABLE `student`( 226 | `student_id` bigint(20) NOT NULL COMMENT '学生ID', 227 | `password` bigint(20) NOT NULL COMMENT '密码', 228 | PRIMARY KEY(`student_id`) 229 | )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生统计表'; 230 | -- 初始化学生数据 231 | INSERT INTO `student`(`student_id`,`password`) 232 | VALUES 233 | (3211200801,346543), 234 | (3211200802,754323), 235 | (3211200803,674554), 236 | (3211200804,542344), 237 | (3211200805,298383), 238 | (3211200806,873973), 239 | (3211200807,193737), 240 | (3211200808,873092); 241 | 242 | ``` 243 | ## 5 根据数据库对象创建实体类。
244 | 第一个开始填充的类当然是entiy包,他是承接我们从数据库里去除数据的类,或者把该类存入数据库,在这里我们创建两个类,一个是Book包(从数据库取出书后放入该包),一个是Appointment(存放从数据库取出的预约书籍信息)。
245 | Book.java 246 | ```java 247 | package com.imooc.appoint.entiy; 248 | 249 | public class Book { 250 | 251 | private long bookId;//图书ID 252 | private String name;//图书名称 253 | private int number;//馆藏数量 254 | private String introd; 255 | public Book() { //为什么要有个无参构造器 256 | } 257 | public Book(long bookId, String name, int number) { 258 | this.bookId = bookId; 259 | this.name = name; 260 | this.number = number; 261 | } 262 | public long getBookId() { 263 | return bookId; 264 | } 265 | public void setBookId(long bookId) { 266 | this.bookId = bookId; 267 | } 268 | public String getName() { 269 | return name; 270 | } 271 | public void setName(String name) { 272 | this.name = name; 273 | } 274 | public int getNumber() { 275 | return number; 276 | } 277 | public void setNumber(int number) { 278 | this.number = number; 279 | } 280 | public String getIntrod() { 281 | return introd; 282 | } 283 | public void setIntrod(String introd) { 284 | this.introd = introd; 285 | } 286 | 287 | @Override 288 | public String toString() { 289 | return "Book [bookId=" + bookId + ", name=" + name + ", number=" + number + ", introd=" + introd + "]"; 290 | } 291 | } 292 | ``` 293 | Appointment.java 294 | ```java 295 | package com.imooc.appoint.entiy; 296 | 297 | import java.util.Date; 298 | 299 | public class Appointment { 300 | private long bookId; 301 | private long studentId; 302 | private Date appointTime; 303 | // 多对一的复合属性 304 | private Book book;// 图书实体 305 | public Appointment(){ 306 | } 307 | public Appointment(long bookId, long studentId, Date appointTime) { 308 | this.bookId = bookId; 309 | this.studentId = studentId; 310 | this.appointTime = appointTime; 311 | } 312 | public long getBookId() { 313 | return bookId; 314 | } 315 | public void setBookId(long bookId) { 316 | this.bookId = bookId; 317 | } 318 | public long getStudentId() { 319 | return studentId; 320 | } 321 | public void setStudentId(long studentId) { 322 | this.studentId = studentId; 323 | } 324 | public Date getAppointTime() { 325 | return appointTime; 326 | } 327 | public void setAppointTime(Date appointTime) { 328 | this.appointTime = appointTime; 329 | } 330 | public Book getBook() { 331 | return book; 332 | } 333 | public void setBook(Book book) { 334 | this.book = book; 335 | } 336 | @Override 337 | public String toString() { 338 | return "Appointment [bookId=" + bookId + ", studentId=" + studentId + ", appointTime=" + appointTime + ", book=" 339 | + book + "]"; 340 | } 341 | } 342 | ``` 343 | 因为我们还打算做一个学生ID、密码验证,所以也得有学生类.
344 | Student.java 345 | ```java 346 | package com.imooc.appoint.entiy; 347 | 348 | public class Student { 349 | private Long studentId; 350 | private Long password; 351 | 352 | public Student(){ 353 | 354 | } 355 | public Student(Long studentId,Long password){ 356 | this.studentId=studentId; 357 | this.password=password; 358 | } 359 | public Long getStudentId() { 360 | return studentId; 361 | } 362 | public void setStudentId(Long studentId) { 363 | this.studentId = studentId; 364 | } 365 | public Long getPassword() { 366 | return password; 367 | } 368 | public void setPassword(Long password) { 369 | this.password = password; 370 | } 371 | 372 | @Override 373 | public String toString() { 374 | return "Student [studentId=" + studentId + ", password=" + password + "]"; 375 | } 376 | } 377 | 378 | ``` 379 | ## 6创建DAO中的类
380 | DAO包中的类主要功能是实现与数据库交互,所以我们需要大的逻辑是:1、学生类与数据库交互;2、预约是与数据库交互;3、查询书时与时与数据库交互。这里大致分为几类,等具体写接口时再去细写。还有就是注意,DAO只是与数据库交互,不能写交互组成的逻辑,这个放在service里面。我们应该站在用户的角度设计DAO接口,至于具体怎么用,后面再写。
381 | BookDao.java 382 | ```java 383 | package com.imooc.appoint.dao; 384 | 385 | import java.util.List; 386 | 387 | import org.apache.ibatis.annotations.Param; 388 | 389 | import com.imooc.appoint.entiy.Book; 390 | 391 | public interface BookDao { 392 | /* 393 | * 根据id查询书 394 | * 395 | */ 396 | Book queryById(long id); 397 | List querySome(String name); 398 | List queryAll(@Param("offset") int offset,@Param("limit") int limit); 399 | 400 | /*减少管存数量 401 | * 用返回值可判断当前库存是否还有书 402 | */ 403 | int reduceNumber(long bookId); 404 | } 405 | 406 | 407 | ``` 408 | AppointmentDao.java 409 | ```java 410 | package com.imooc.appoint.dao; 411 | 412 | import java.util.List; 413 | 414 | import org.apache.ibatis.annotations.Param; 415 | 416 | import com.imooc.appoint.entiy.Appointment; 417 | 418 | public interface AppointmentDao { 419 | //通过图书ID和学生ID预约书籍,并插入 420 | int insertAppointment(@Param("bookId") long bookId, @Param("studentId") long studentId); 421 | 422 | //通过一个学生ID查询已经预约了哪些书。 423 | List quaryAndReturn(long studentId); 424 | 425 | } 426 | 427 | ``` 428 | StudentDao.java 429 | ```java 430 | package com.imooc.appoint.dao; 431 | 432 | import org.apache.ibatis.annotations.Param; 433 | 434 | import com.imooc.appoint.entiy.Student; 435 | 436 | public interface StudentDao { 437 | /** 438 | * 向数据库验证输入的密码是否正确 439 | */ 440 | Student quaryStudent(@Param("studentId") long studentId, @Param("password") long password); 441 | } 442 | 443 | ``` 444 | ## 7我们暂时先不管以上接口实现,先为DAO配置入框架,实现spring与mybatis的整合。
445 | 因为spring的配置太多,我们这里分三层,分别是dao service web。我们这里先写spring-dao.xml,其他的等我们实现相应包后再去配置。 446 | 配置时,主要注意一下几个方面:
447 | 1、读入数据库连接相关参数(可选)
448 | 2、配置数据连接池
449 | 3、配置连接属性,可以不读配置项文件直接在这里写死
450 | 4、配置c3p0,只配了几个常用的
451 | 5、配置SqlSessionFactory对象(mybatis)
452 | 6、扫描dao层接口,动态实现dao接口,也就是说不需要daoImpl,sql和参数都写在xml文件上
453 | spring-dao.xml 454 | ```java 455 | 456 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | ``` 506 | ### 配置jdbc.properties文件
507 | ```java 508 | jdbc.driver=com.mysql.jdbc.Driver 509 | jdbc.url=jdbc:mysql://127.0.0.1:3306/ssmbookappoint?useUnicode=true&characterEncoding=utf8 510 | jdbc.username= 511 | jdbc.password= 512 | ``` 513 | 第一次上传忘记去掉用户名密码了,好险!大家用的时候填上自己的用户名、密码。
514 | ### 配置mybatis。
515 | 所以需要配置mybatis核心文件,在recources文件夹里新建mybatis-config.xml文件。
516 | 517 | 1、使用自增主键
518 | 2、使用列别名
519 | 3、开启驼峰命名转换 create_time -> createTime
520 | mybatis-config.xml 521 | ```java 522 | 523 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | ``` 540 | 541 | ## 8配置实现接口的xml
542 | 我们要开始写DAO接口的实现类,因为我们配置扫描sql配置文件路径是:mapper下的xml,所有我们应该在resourse下新建mapper文件夹,在这里存放实现DAO接口的各种xml
543 | BookDao.xml 544 | ```java 545 | 546 | 549 | 550 | 562 | 563 | 571 | 572 | 584 | 585 | 586 | UPDATE book 587 | SET number = number - 1 588 | WHERE 589 | book_id = #{bookId} 590 | AND number > 0 591 | 592 | 593 | 594 | ``` 595 | AppointmentDao.xml 596 | ```java 597 | 598 | 601 | 602 | 603 | 604 | INSERT ignore INTO appointment (book_id, student_id) 605 | VALUES (#{bookId}, #{studentId}) 606 | 607 | 610 | 611 | 628 | 645 | 646 | 647 | ``` 648 | StudentDao.java 649 | ```java 650 | 651 | 654 | 655 | 665 | 666 | 667 | ``` 668 | 到此为止,我们dao层的开发就算结束了,大家可以写个测试类,测试一下。(我没写,哈哈),要实现预约功能还得有更多详细的逻辑组织,这个功能将他放在service中,他把DAO中与数据库交互的功能组织成可以用的详细逻辑。提供给上层web调用。
669 | ## 8 service层
670 | ### 首先写service接口类
671 | BookService.java 672 | ```java 673 | package com.imooc.appoint.service; 674 | 675 | import java.util.List; 676 | 677 | import com.imooc.appoint.dto.AppointExecution; 678 | import com.imooc.appoint.entiy.Appointment; 679 | import com.imooc.appoint.entiy.Book; 680 | import com.imooc.appoint.entiy.Student; 681 | 682 | public interface BookService { 683 | /** 684 | * 查询一本图书 685 | * 686 | * @param bookId 687 | * @return 688 | */ 689 | Book getById(long bookId); 690 | /** 691 | * 查询所有图书 692 | * 693 | * @return 694 | */ 695 | List getList(); 696 | /** 697 | * 登陆时查询数据库是否有该学生记录。 698 | */ 699 | Student validateStu(Long studentId,Long password); 700 | /**按照图书名称查询 701 | * 按条件搜索图书 702 | * 703 | */ 704 | List getSomeList(String name); 705 | /* 706 | * 查看某学生预约的所有图书 707 | * 708 | */ 709 | List getAppointByStu(long studentId); 710 | /** 711 | * 预约图书 712 | * 713 | * @param bookId 714 | * @param studentId 715 | * @return 716 | */ 717 | AppointExecution appoint(long bookId, long studentId);//返回预约成功的实体类 718 | } 719 | ``` 720 | 大家可以看到,这个借口类中基本和DAO中的没啥区别,有区别的是某些类他是在dao上更进一步,需要多个dao类一起组织,或者在加入其它逻辑才能实现
721 | 为了实现BookService的借口,我们得写BookServiceImpl类。但是想让我们想想,为了写BookServiceImpl,我们需要什么,上面我们已经写出预约成功的实体类是AppointExecution,所以当然我们得写出该类,因为该类交互service和web,对这类有点像entiy包我们管叫bto包(bto包和其他包一起存放在appoint下)。对于AppointExecution来说,作用就是预约成功后给web层提供返回的信息。(就是返回预约成功、预约失败、无库存、之类的信息)
722 | ```java 723 | package com.imooc.appoint.dto; 724 | import com.imooc.appoint.enums.AppointStateEnum; 725 | 726 | public class AppointExecution { 727 | 728 | // 图书ID 729 | private long bookId; 730 | 731 | // 预约结果状态 732 | private int state; 733 | 734 | // 状态标识 735 | private String stateInfo; 736 | 737 | public AppointExecution() { 738 | } 739 | 740 | // 预约失败的构造器 741 | public AppointExecution(long bookId, AppointStateEnum stateEnum) { 742 | this.bookId = bookId; 743 | this.state = stateEnum.getState(); 744 | this.stateInfo = stateEnum.getStateInfo(); 745 | } 746 | 747 | //set get 方法! 748 | public long getBookId() { 749 | return bookId; 750 | } 751 | 752 | public void setBookId(long bookId) { 753 | this.bookId = bookId; 754 | } 755 | 756 | public int getState() { 757 | return state; 758 | } 759 | 760 | public void setState(int state) { 761 | this.state = state; 762 | } 763 | 764 | public String getStateInfo() { 765 | return stateInfo; 766 | } 767 | 768 | public void setStateInfo(String stateInfo) { 769 | this.stateInfo = stateInfo; 770 | } 771 | 772 | @Override 773 | public String toString() { 774 | return "AppointExecution [bookId=" + bookId + ", state=" + state + ", stateInfo=" + stateInfo+"]"; 775 | } 776 | } 777 | ``` 778 | 除此之外,我们在预约图书时可能出现异常,例如重复预约、无库存、和其他异常,我们需要事先设计好异常类,来接收这类异常,方便处理,而不是直接报错。因此在appoint包下新建excption包,报下新建三个类:AppoinException.java;NoNumberException.java;RepeatAppoint.java
779 | AppoinException.java 780 | ```java 781 | package com.imooc.appoint.exception; 782 | //预约义务异常 783 | public class AppointException extends RuntimeException{ 784 | public AppointException(String message) { 785 | super(message); 786 | } 787 | 788 | public AppointException(String message, Throwable cause) { 789 | super(message, cause); 790 | } 791 | } 792 | 793 | ``` 794 | NoNumberException.java 795 | ```java 796 | package com.imooc.appoint.exception; 797 | 798 | //库存不足异常 799 | public class NoNumberException extends RuntimeException{ 800 | public NoNumberException(String message) { 801 | super(message); 802 | } 803 | 804 | public NoNumberException(String message, Throwable cause) { 805 | super(message, cause); 806 | } 807 | 808 | } 809 | 810 | ``` 811 | RepeatAppoint.java 812 | ```java 813 | package com.imooc.appoint.exception; 814 | //重复预约异常 815 | public class RepeatAppointException extends RuntimeException{ 816 | public RepeatAppointException(String message) { 817 | super(message); 818 | } 819 | 820 | public RepeatAppointException(String message, Throwable cause) { 821 | super(message, cause); 822 | } 823 | } 824 | ``` 825 | 现在可以写接口的实现类啦:BookServiceImpl.java
826 | ```java 827 | package com.imooc.appoint.service.Impl; 828 | 829 | import java.util.List; 830 | 831 | import org.slf4j.Logger; 832 | import org.slf4j.LoggerFactory; 833 | import org.springframework.beans.factory.annotation.Autowired; 834 | import org.springframework.stereotype.Service; 835 | import org.springframework.transaction.annotation.Transactional; 836 | 837 | import com.imooc.appoint.dao.AppointmentDao; 838 | import com.imooc.appoint.dao.BookDao; 839 | import com.imooc.appoint.dao.StudentDao; 840 | import com.imooc.appoint.dto.AppointExecution; 841 | import com.imooc.appoint.entiy.Appointment; 842 | import com.imooc.appoint.entiy.Book; 843 | import com.imooc.appoint.entiy.Student; 844 | import com.imooc.appoint.enums.AppointStateEnum; 845 | import com.imooc.appoint.exception.AppointException; 846 | import com.imooc.appoint.exception.NoNumberException; 847 | import com.imooc.appoint.exception.RepeatAppointException; 848 | import com.imooc.appoint.service.BookService; 849 | 850 | @Service 851 | public class BookServiceImpl implements BookService{ 852 | private Logger logger=LoggerFactory.getLogger(this.getClass()); 853 | @Autowired 854 | private BookDao bookDao; 855 | @Autowired 856 | private AppointmentDao appointmentDao; 857 | @Autowired 858 | private StudentDao studentDao; 859 | @Override 860 | public Book getById(long bookId) { 861 | return bookDao.queryById(bookId); 862 | } 863 | @Override 864 | public List getList() { 865 | return bookDao.queryAll(0, 1000); 866 | } 867 | @Override 868 | public Student validateStu(Long studentId,Long password){ 869 | return studentDao.quaryStudent(studentId, password); 870 | } 871 | @Override 872 | public List getSomeList(String name) { 873 | 874 | return bookDao.querySome(name); 875 | } 876 | @Override 877 | public List getAppointByStu(long studentId) {//DOTO 878 | return appointmentDao.quaryAndReturn(studentId); 879 | 880 | } 881 | @Override 882 | @Transactional 883 | public AppointExecution appoint(long bookId, long studentId) {//在Dao的基础上组织逻辑,形成与web成交互用的方法 884 | try{ //返回成功预约的类型。 885 | int update=bookDao.reduceNumber(bookId);//减库存 886 | if(update<=0){//已经无库存! 887 | throw new NoNumberException("no number"); 888 | }else{ 889 | //执行预约操作 890 | int insert=appointmentDao.insertAppointment(bookId, studentId); 891 | if(insert<=0){//重复预约 892 | throw new RepeatAppointException("repeat appoint"); 893 | }else{//预约成功 894 | return new AppointExecution(bookId,AppointStateEnum.SUCCESS); 895 | } 896 | 897 | } 898 | } catch (NoNumberException e1) { 899 | throw e1; 900 | } catch (RepeatAppointException e2) { 901 | throw e2; 902 | } catch (Exception e) { 903 | logger.error(e.getMessage(), e); 904 | // 所有编译期异常转换为运行期异常 905 | throw new AppointException("appoint inner error:" + e.getMessage()); 906 | } 907 | } 908 | } 909 | 910 | ``` 911 | ### 又到了我们写service层配置的时候!
912 | 该xml依然位于resourse下的spring包下
913 | spring-service.xml 914 | ```java 915 | 916 | 926 | 927 | 928 | 929 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | ``` 938 | ## 9web层
939 | 现在我们一起看看web层该如何组织。
940 | 在写具体的代码之前,先配置web层,在这里主要实现的作用是:
941 | 1、开启SpringMVC注解模式,可以使用@RequestMapping,@PathVariable,@ResponseBody等
942 | 2、对静态资源处理,如js,css,jpg等
943 | 3、配置jsp 显示ViewResolver,例如在controller中某个方法返回一个string类型的"login",实际上会返回"/WEB-INF/login.jsp"
944 | 4、扫描web层 @Controller
945 | 详细见xml中每一步的注释
946 | spring-web.xml
947 | ```java 948 | 949 | 959 | 960 | 961 | 965 | 966 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | ``` 982 | 当然我们必须修改web.xml文件,它在webapp的WEB-INF下,这个文件配置servlet,并初始化,指定扫描spring相关的配置,最后我们将所有的url都拦截下来。 983 | web.xml
984 | ```java 985 | 989 | 990 | BookAppointment-dispatcher 991 | org.springframework.web.servlet.DispatcherServlet 992 | 993 | contextConfigLocation 994 | classpath:spring/spring-*.xml 995 | 996 | 997 | 998 | BookAppointment-dispatcher 999 | / 1000 | 1001 | 1002 | 1003 | 1004 | ``` 1005 | 因为在运行时,我们经常会查看日志什么的,所以我们把这个配置进去
1006 | logback.xml 1007 | ```java 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | ``` 1022 | 最后我们开始组织我们web的逻辑,也就是具体的controller层代码的编写。
1023 | 这一层中与我们的前段联系的较为紧密,大家可以边写边看效果,再调试。 1024 | ```java 1025 | package com.imooc.appoint.web; 1026 | 1027 | import java.io.IOException; 1028 | import java.util.ArrayList; 1029 | import java.util.HashMap; 1030 | import java.util.List; 1031 | import java.util.Map; 1032 | 1033 | import javax.servlet.ServletException; 1034 | import javax.servlet.http.HttpServletRequest; 1035 | import javax.servlet.http.HttpServletResponse; 1036 | 1037 | import org.apache.ibatis.annotations.Param; 1038 | import org.slf4j.Logger; 1039 | import org.slf4j.LoggerFactory; 1040 | import org.springframework.beans.factory.annotation.Autowired; 1041 | import org.springframework.stereotype.Controller; 1042 | import org.springframework.ui.Model; 1043 | import org.springframework.web.bind.annotation.PathVariable; 1044 | import org.springframework.web.bind.annotation.RequestMapping; 1045 | import org.springframework.web.bind.annotation.RequestMethod; 1046 | import org.springframework.web.bind.annotation.RequestParam; 1047 | import org.springframework.web.bind.annotation.ResponseBody; 1048 | 1049 | import com.imooc.appoint.dto.AppointExecution; 1050 | import com.imooc.appoint.dto.Result; 1051 | import com.imooc.appoint.entiy.Appointment; 1052 | import com.imooc.appoint.entiy.Book; 1053 | import com.imooc.appoint.entiy.Student; 1054 | import com.imooc.appoint.enums.AppointStateEnum; 1055 | import com.imooc.appoint.service.BookService; 1056 | import com.imooc.appoint.exception.RepeatAppointException; 1057 | import com.imooc.appoint.exception.NoNumberException; 1058 | 1059 | 1060 | @Controller 1061 | @RequestMapping("/books") 1062 | public class BookController { 1063 | private Logger logger=LoggerFactory.getLogger(this.getClass()); 1064 | @Autowired 1065 | private BookService bookService; 1066 | //获取图书列表 1067 | @RequestMapping(value="/list",method = RequestMethod.GET) 1068 | private String List(Model model){ 1069 | List list = bookService.getList(); 1070 | model.addAttribute("list", list); 1071 | 1072 | return "list"; 1073 | } 1074 | //搜索是否有某图书 1075 | @RequestMapping(value="/search",method = RequestMethod.POST) 1076 | private void search(HttpServletRequest req,HttpServletResponse resp) 1077 | throws ServletException, IOException{ 1078 | //接收页面的值 1079 | String name=req.getParameter("name"); 1080 | name=name.trim(); 1081 | //向页面传值 1082 | req.setAttribute("name", name); 1083 | req.setAttribute("list", bookService.getSomeList(name)); 1084 | req.getRequestDispatcher("/WEB-INF/jsp/list.jsp").forward(req, resp); 1085 | } 1086 | //查看某图书的详细情况 1087 | @RequestMapping(value = "/{bookId}/detail", method = RequestMethod.GET) 1088 | private String detail(@PathVariable("bookId") Long bookId, Model model){ 1089 | if(bookId==null){ 1090 | return "redict:/book/list"; 1091 | } 1092 | Book book=bookService.getById(bookId); 1093 | if(book==null){ 1094 | return "forward:/book/list"; 1095 | } 1096 | model.addAttribute("book",book); 1097 | System.out.println(book); 1098 | return "detail"; 1099 | } 1100 | //验证输入的用户名、密码是否正确 1101 | @RequestMapping(value="/verify", method = RequestMethod.POST, produces = { 1102 | "application/json; charset=utf-8" }) 1103 | @ResponseBody 1104 | private Map validate(Long studentId,Long password){ //(HttpServletRequest req,HttpServletResponse resp){ 1105 | Map resultMap=new HashMap(); 1106 | Student student =null; 1107 | System.out.println("验证函数"); 1108 | student =bookService.validateStu(studentId,password); 1109 | 1110 | System.out.println("输入的学号、密码:"+studentId+":"+password); 1111 | System.out.println("查询到的:"+student.getStudentId()+":"+student.getPassword()); 1112 | 1113 | if(student!=null){ 1114 | System.out.println("SUCCESS"); 1115 | resultMap.put("result", "SUCCESS"); 1116 | return resultMap; 1117 | }else{ 1118 | resultMap.put("result", "FAILED"); 1119 | return resultMap; 1120 | } 1121 | 1122 | } 1123 | //执行预约的逻辑 1124 | @RequestMapping(value = "/{bookId}/appoint", method = RequestMethod.POST, produces = { 1125 | "application/json; charset=utf-8" }) 1126 | @ResponseBody 1127 | private Result execute(@PathVariable("bookId") Long bookId,@RequestParam("studentId") Long studentId){ 1128 | Result result; 1129 | AppointExecution execution=null; 1130 | 1131 | try{//手动try catch,在调用appoint方法时可能报错 1132 | execution=bookService.appoint(bookId, studentId); 1133 | result=new Result(true,execution); 1134 | return result; 1135 | 1136 | } catch(NoNumberException e1) { 1137 | execution=new AppointExecution(bookId,AppointStateEnum.NO_NUMBER); 1138 | result=new Result(true,execution); 1139 | return result; 1140 | }catch(RepeatAppointException e2){ 1141 | execution=new AppointExecution(bookId,AppointStateEnum.REPEAT_APPOINT); 1142 | result=new Result(true,execution); 1143 | return result; 1144 | }catch (Exception e){ 1145 | execution=new AppointExecution(bookId,AppointStateEnum.INNER_ERROR); 1146 | result=new Result(true,execution); 1147 | return result; 1148 | } 1149 | } 1150 | @RequestMapping(value ="/appoint") 1151 | private String appointBooks(@RequestParam("studentId") long studentId,Model model){ 1152 | 1153 | List appointList=new ArrayList(); 1154 | appointList=bookService.getAppointByStu(studentId); 1155 | model.addAttribute("appointList", appointList); 1156 | 1157 | return "appointBookList"; 1158 | } 1159 | 1160 | } 1161 | 1162 | ``` 1163 | 为了把执行预约逻辑是否返回的不同信息封装起来,我们创建一个Result类,它是类型T的集合。
1164 | Result.java 1165 | ```java 1166 | package com.imooc.appoint.dto; 1167 | /** 1168 | * 封装json对象,所有返回结果都使用它 1169 | */ 1170 | public class Result { 1171 | private boolean success;// 是否成功标志 1172 | 1173 | private T data;// 成功时返回的数据 1174 | 1175 | private String error;// 错误信息 1176 | 1177 | public Result() { 1178 | } 1179 | 1180 | // 成功时的构造器 1181 | public Result(boolean success, T data) { 1182 | this.success = success; 1183 | this.data = data; 1184 | } 1185 | 1186 | // 错误时的构造器 1187 | public Result(boolean success, String error) { 1188 | this.success = success; 1189 | this.error = error; 1190 | } 1191 | 1192 | 1193 | public boolean isSuccess() { 1194 | return success; 1195 | } 1196 | 1197 | public void setSuccess(boolean success) { 1198 | this.success = success; 1199 | } 1200 | 1201 | public T getData() { 1202 | return data; 1203 | } 1204 | 1205 | public void setData(T data) { 1206 | this.data = data; 1207 | } 1208 | 1209 | public String getError() { 1210 | return error; 1211 | } 1212 | 1213 | public void setError(String error) { 1214 | this.error = error; 1215 | } 1216 | 1217 | } 1218 | ``` 1219 | 为了给web显示预约后的反馈信息,我们建立一个常量数据字典类存放这些要反馈给客户的信息
1220 | AppointStateEnum.java 1221 | ```java 1222 | package com.imooc.appoint.enums; 1223 | 1224 | //使用枚举表述常量数据字典,我们先定义几个预约图书操作返回码的数据字典,也就是我们要返回给客户端的信息。 1225 | public enum AppointStateEnum { 1226 | SUCCESS(1, "预约成功"), NO_NUMBER(0, "库存不足"), REPEAT_APPOINT(-1, "重复预约"), INNER_ERROR(-2, "系统异常"); 1227 | 1228 | private int state; 1229 | 1230 | private String stateInfo; 1231 | 1232 | private AppointStateEnum(int state, String stateInfo) { 1233 | this.state = state; 1234 | this.stateInfo = stateInfo; 1235 | } 1236 | 1237 | public int getState() { 1238 | return state; 1239 | } 1240 | 1241 | public String getStateInfo() { 1242 | return stateInfo; 1243 | } 1244 | 1245 | public static AppointStateEnum stateOf(int index) { 1246 | for (AppointStateEnum state : values()) { 1247 | if (state.getState() == index) { 1248 | return state; 1249 | } 1250 | } 1251 | return null; 1252 | } 1253 | } 1254 | ``` 1255 | 到此为止,我们后端写的差不多了,下面是前段页面的开发,其实前段和controller中的方法开发是相互嵌套的,在写方法的同时,写js或者jsp文件。这样逻辑才能连贯。再此用bootstrap这种轻量一站式框架开发前段,能死前端技术不怎么好的童鞋也能开发出还看得过去的页面。
1256 | 话不多少,我们上代码:
1257 | list.jsp 1258 | ```java 1259 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 1260 | <%@include file="common/tag.jsp"%> 1261 | 1262 | 1263 | 1264 | 图书列表 1265 | <%@include file="common/head.jsp" %> 1266 | 1267 | 1268 |
1269 |
1270 |
1271 |

图书列表

1272 |
1273 |
1274 |
1275 | 1276 | 1277 | 1278 | 1279 | 1282 | 1285 | 1286 | 1287 |
图书名称: 1280 | 1281 | 1283 | 1284 |
1288 |
1289 |
1290 | 1291 | 1292 |
1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 |
图书ID图书名称馆藏数量详细
${sk.bookId}${sk.name}${sk.number}详细
1313 |
1314 | 1315 | 1316 |
1317 |
1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | ``` 1326 | detail.jsp 1327 | ```java 1328 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 1329 | <%@include file="common/tag.jsp" %> 1330 | 1331 | 1332 | 1333 | 预约详情页 1334 | <%@include file="common/head.jsp" %> 1335 | 1336 | 1337 |
1338 |
1339 |
1340 |

图书详情

1341 |
1342 |
1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1351 | 1352 | 1353 | 1354 | 1355 | 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 |
图书ID图书名称图书简介剩余数量预约数量
${book.bookId}${book.name}${book.introd}${book.number }1
1363 |
1364 |
1365 |

1366 | 1367 | 1368 | 1369 | 查看我的已预约书籍 1370 |

1371 |
1372 |
1373 | 1374 |
1375 | 1376 | 1409 | 1410 | 1411 | <%--jQery文件,务必在bootstrap.min.js之前引入--%> 1412 | 1413 | 1414 | <%--使用CDN 获取公共js http://www.bootcdn.cn/--%> 1415 | <%--jQuery Cookie操作插件--%> 1416 | 1417 | <%--jQuery countDown倒计时插件--%> 1418 | 1419 | 1420 | 1421 | 1422 | 1431 | 1432 | ``` 1433 | bookappointment.js 1434 | ```javascript 1435 | var bookappointment={ 1436 | //封装相关ajax的url 1437 | URL:{ 1438 | appoint:function(bookId,studentId){ 1439 | return '/books/'+bookId+'/appoint?studentId='+studentId; 1440 | }, 1441 | verify:function(){ 1442 | return '/books'+'/verify'; 1443 | } 1444 | }, 1445 | 1446 | //验证学号和密码 1447 | validateStudent:function(studentId,password){ 1448 | console.log("studentId"+studentId); 1449 | if(!studentId||!password){ 1450 | return "nothing"; 1451 | }else if(studentId.length!=10 ||isNaN(studentId)||password.length!=6 ||isNaN(password)){ 1452 | return "typerror"; 1453 | }else { 1454 | if(bookappointment.verifyWithDatabase(studentId, password)){ 1455 | console.log("验证成功!"); 1456 | return "success"; 1457 | }else{ 1458 | console.log("验证失败!"); 1459 | return "mismatch"; 1460 | } 1461 | } 1462 | }, 1463 | //将学号和用户名与数据库匹配 1464 | verifyWithDatabase:function(studentId,password){ 1465 | var result=false; 1466 | var params={}; 1467 | params.studentId=studentId; 1468 | params.password=password; 1469 | console.log("params.password:"+params.password); 1470 | var verifyUrl=bookappointment.URL.verify(); 1471 | $.ajax({ 1472 | type:'post', 1473 | url:verifyUrl, 1474 | data:params, 1475 | datatype:'josn', 1476 | async:false, //同步调用,保证先执行result=true,后再执行return result; 1477 | success:function(data){ 1478 | if(data.result=='SUCCESS'){ 1479 | window.location.reload(); 1480 | //弹出登录成功! 1481 | alert("登陆成功!"); 1482 | result=true; 1483 | }else{ 1484 | result=false; 1485 | } 1486 | } 1487 | }); 1488 | console.log("我是验证结果:"+result); 1489 | return result; 1490 | 1491 | }, 1492 | 1493 | //预定图书逻辑 1494 | detail:{ 1495 | //预定也初始化 1496 | init:function(params){ 1497 | var bookId=params['bookId']; 1498 | console.log("我是js文件!"); 1499 | 1500 | var studentId=$.cookie('studentId'); 1501 | var password=$.cookie('password'); 1502 | if(!studentId||!password){ 1503 | //设置弹出层属性 1504 | var IdAndPasswordModal=$('#varifyModal'); 1505 | IdAndPasswordModal.modal({ 1506 | show: true,//显示弹出层 1507 | backdrop: 'static',//禁止位置关闭 1508 | keyboard: false//关闭键盘事件 1509 | }); 1510 | $('#studentBtn').click(function (){ 1511 | studentId=$('#studentIdKey').val(); 1512 | console.log("studentId:"+studentId); 1513 | password=$('#passwordKey').val(); 1514 | console.log("password:"+password); 1515 | //调用validateStudent函数验证用户id和密码。 1516 | var temp=bookappointment.validateStudent(studentId,password); 1517 | console.log(temp); 1518 | if(temp=="nothing"){ 1519 | $('#studentMessage').hide().html('').show(300); 1520 | }else if(temp=="typerror"){ 1521 | $('#studentMessage').hide().html('').show(300); 1522 | }else if(temp=="mismatch"){ 1523 | console.log("已经调用验证函数!"); 1524 | $('#studentMessage').hide().html('').show(300); 1525 | }else if(temp=="success"){ 1526 | //学号与密码匹配正确,将学号密码保存在cookie中。不设置cookie过期时间,这样即为session模式,关闭浏览器就不保存密码了。 1527 | $.cookie('studentId', studentId, { path: '/books'}); 1528 | $.cookie('password', password, { path: '/books'}); 1529 | // 跳转到预约逻辑 1530 | var appointbox=$('#appoint-box'); 1531 | bookappointment.appointment(bookId,studentId,appointbox); 1532 | } 1533 | }); 1534 | }else{ 1535 | var appointbox=$('#appoint-box'); 1536 | bookappointment.appointment(bookId,studentId,appointbox); 1537 | } 1538 | } 1539 | }, 1540 | appointment:function(bookId,studentId, node){ 1541 | console.log("我执行预约的方法!" ); 1542 | node.html(''); 1543 | 1544 | var appointmentUrl = bookappointment.URL.appoint(bookId,studentId); 1545 | console.log("appointmentUrl:"+appointmentUrl); 1546 | //绑定一次点击事件 1547 | $('#appointmentBtn').one('click', function () { 1548 | //执行预约请求 1549 | //1、先禁用请求 1550 | $(this).addClass('disabled'); 1551 | //2、发送预约请求执行预约 1552 | $.post(appointmentUrl,{},function(result){ //Ajax强大之处,向Controller方法提出请求和返回结果在一处! 1553 | if(result && result['success']){ //同时还可以连续取对象的子对象! 1554 | var appointResult=result['data']; 1555 | console.log("appointResult"+appointResult); 1556 | var state=appointResult['state']; 1557 | console.log("state"+state); 1558 | var stateInfo=appointResult['stateInfo']; 1559 | console.log("stateInfo"+stateInfo); 1560 | //显示预约结果 把结果显示给页面,完成了jsp的工作 1561 | node.html(''+stateInfo+''); 1562 | } //因为公用一个node所以,用来显示“stateInfo”时就不会显示上面的“预约” 1563 | console.log('result'+result); 1564 | }); 1565 | }); 1566 | 1567 | 1568 | } 1569 | } 1570 | ``` 1571 | appointBookList.jsp 1572 | ```java 1573 | <%@page contentType="text/html; charset=UTF-8" language="java" %> 1574 | <%@include file="common/tag.jsp"%> 1575 | 1576 | 1577 | 1578 | 预约图书列表 1579 | <%@include file="common/head.jsp" %> 1580 | 1581 | 1582 |
1583 |
1584 |
1585 |

您已预约图书列表

1586 |
1587 |
1588 | 1589 | 1590 | 1591 | 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 |
预定学号预约时间图书ID图书名称图书简介预约数量
${sk.studentId}${sk.appointTime}${sk.bookId}${sk.book.getName()}${sk.book.getIntrod()}1
1612 |
1613 |
1614 |
1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 | 1622 | ``` 1623 | 到此为止,所有的开发就已经结束,已经把所有源代码上传至github,需要的可以去下载,喜欢就给个star吧。
1624 | 1625 | 1626 | 1627 | 1628 | --------------------------------------------------------------------------------