SpringBoot-Web 整合案例讲解(图书管理系统)
0. 项目预览
1. 创建项目,添加依赖
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. 配置 application.yml
server:
port: 80
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/bookdb?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
username: root
password: 123456
thymeleaf:
cache: false
mode: HTML5
prefix: classpath:/templates/
suffix: .html
encoding: UTF-8
mybatis-plus:
mapper-locations: classpath*:/mapper/*.xml
type-aliases-package: com.jhzhong.domain
configuration:
# 开启驼峰式命名
map-underscore-to-camel-case: true
# 开启 SQL 执行日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3. 创建数据库模型
根据项目需求,数据库模型简要设计如下:
表1:用户信息表 t_user
字段名 | 类型 | 约束 | 描述 |
---|---|---|---|
id | int | 主键,自增长 | 用户id |
username | varchar(32) | 必填,唯一 | 用户名,登录名 |
password | varchar(100) | 必填 | 用户密码 |
real_name | Varchar(32) | 非必填 | 真实姓名 |
表2:图书信息表 t_book
字段名 | 类型 | 约束 | 描述 |
---|---|---|---|
id | int | 主键,自增长 | 图书id |
name | varchar(100) | 必填 | 图书标题 |
author | varchar(32) | 非必填 | 作者 |
publisher | varchar(32) | 非必填 | 出版社 |
publish_date | date | 非必填 | 出版日期 |
price | decimal(10,2) | 非必填 | 单价 |
create_time | datetime | 必填 | 记录创建时间 |
update_time | datetime | 必填 | 记录更新时间 |
SQL脚本:
-- ----------------------------
-- Table structure for t_book
-- ----------------------------
DROP TABLE IF EXISTS `t_book`;
CREATE TABLE `t_book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`author` varchar(32) NOT NULL,
`publisher` varchar(32) DEFAULT NULL,
`publish_date` date DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
`create_time` datetime NOT NULL,
`update_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2065866755 DEFAULT CHARSET=utf8 COMMENT='书籍表';
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(30) NOT NULL COMMENT '用户名',
`real_name` varchar(32) DEFAULT NULL COMMENT '真实姓名',
`password` varchar(200) NOT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表';
4. 项目需求
》完成管理员登录与注册功能
》完成图书列表管理页图书的增删改查功能
4.1 注册
接口地址:http://localhost:80/users/register
请求类型:POST
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
username | String | 是 | 用户名 |
Password | String | 是 | 密码 |
响应:
注册成功,返回登录页
4.2 登录
接口地址:http://localhost:80/users/login
请求类型:POST
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
username | String | 是 | 用户名 |
Password | String | 是 | 密码 |
响应:
登录成功,跳转到图书列表页
登录失败,跳转到登录页
4.3 图书列表页查询
接口地址:http://localhost:80/books/list
请求类型:GET
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
pageNum | int | 否(默认0) | 当前页 |
pageSize | int | 否(默认5) | 页面数据显示条数 |
响应:查询成功,跳转列表页
返回参数:
参数名称 | 类型 | 描述 |
---|---|---|
books | List<Object> | 图书信息列表 |
pageInfo | Object | 图书列表页分页对象 |
返回参数示例:
4.4 根据图书名称查询
接口地址:http://localhost:80/books/list
请求类型:GET
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
pageNum | int | 否(默认0) | 当前页 |
pageSize | int | 否(默认5) | 页面数据显示条数 |
name | String | 否(默认查所有) | 图书名称 |
响应:查询成功,跳转列表页
返回参数:
参数名称 | 类型 | 描述 |
---|---|---|
books | List<Object> | 图书信息列表 |
pageInfo | Object | 图书列表页分页对象 |
返回参数示例:
4.5 添加图书
接口地址:http://localhost:80/books/add
请求类型:POST
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
name | String | 是 | 图书标题 |
author | String | 是 | 图书作者 |
publisher | String | 是 | 出版社名称 |
publishDate | Date | 是 | 出版日期 |
price | BigDecimal(10,2) | 是 | 单价 |
响应:插入成功,跳转列表页
4.6 根据图书 ID 查询
接口地址:http://localhost:80/books/edit/{id}
请求类型:GET
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
id | int | 是 | 图书id |
响应:查询成功,将结果绑定到编辑页面进行数据回显
返回参数示例:
4.7 修改图书
接口地址:http://localhost:80/books/edit/{id}
请求类型:GET
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
id | Int | 是 | 图书id |
name | String | 是 | 图书标题 |
author | String | 是 | 图书作者 |
publisher | String | 是 | 出版社名称 |
publishDate | Date | 是 | 出版日期 |
price | BigDecimal(10,2) | 是 | 单价 |
响应:修改成功,跳转列表页
4.8 删除图书
接口地址:http://localhost:80/books/delete/{id}
请求类型:GET
请求参数:
参数名称 | 类型 | 必填 | 描述 |
---|---|---|---|
id | Int | 是 | 图书id |
响应:修改成功,跳转列表页
5. 项目实现
5.1 实体类
创建com.jhzhong.domain.User
、com.jhzhong.domain.Book
和 com.jhzhong.vo.BookVo
类
// User 类
@Data
@TableName(value = "t_user")
public class User {
@TableId(type = IdType.AUTO)
private Integer id;
private String username;
private String password;
private String realName;
}
// Book 类
@Data
@TableName(value = "t_book")
public class Book {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private String author;
private String publisher;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date publishDate;
private BigDecimal price;
private Date createTime;
private Date updateTime;
}
// BookVo 类
@Data
public class BookVo {
private Integer pageNum=0;
private Integer pageSize=5;
private String name;
}
5.2 Mapper 接口层
创建 com.jhzhong.dao.IUserDao
接口和com.jhzhong.dao.IBookDao
继承 BaseMapper<T>
// com.jhzhong.dao.IUserDao
@Mapper
public interface IUserDao extends BaseMapper<User> {}
// com.jhzhong.dao.IBookDao
@Mapper
public interface IBookDao extends BaseMapper<Book> {}
5.3 Service 接口层
创建com.jhzhong.service.IUserService
接口和 com.jhzhong.service.IBookService
// com.jhzhong.service.IUserService
public interface IUserService {
/**
* 用户登录
* @param user 登录参数(用户名,密码)
* @return 登录成功,返回当前登录对象信息
*/
User login(User user);
/**
* 用户注册
* @param user 注册参数(用户名,密码,其他注册信息等)
* @return 登录成功返回 true 否则 false
*/
Boolean register(User user);
}
// com.jhzhong.service.IBookService
public interface IBookService {
// 根据图书名称查询
Book queryBookByName(String name);
// 根据图书 id 查询
BookDto queryBookById(Integer id);
// 查询所有图书列表
Page<Book> getListBooks(BookVo bookVo);
// 添加图书
Boolean addBook(Book book);
// 编辑图书
Boolean editBook(Book book);
// 删除图片
Boolean delBook(Integer id);
}
5.4 Service 实现层
创建 com.jhzhong.service.impl.UserServiceImpl
和 com.jhzhong.service.impl.BookServiceImpl
并实现上面的接口
// com.jhzhong.service.impl.UserServiceImpl
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private IUserDao userDao;
/**
* 用户登录
* @param user 登录参数(用户名,密码)
* @return 登录成功, 返回当前登录对象信息
*/
@Override
public User login(User user) {
HashMap<String, Object> map = new HashMap<>();
map.put("username",user.getUsername());
map.put("password", user.getPassword());
List<User> users = userDao.selectByMap(map);
return users.isEmpty() ? null : users.get(0);
}
/**
* 用户注册
*
* @param user 注册参数(用户名,密码,其他注册信息等)
* @return 登录成功返回 true 否则 false
*/
@Override
public Boolean register(User user) {
int rows = userDao.insert(user);
return rows > 0;
}
}
// com.jhzhong.service.impl.BookServiceImpl
@Service
public class BookServiceImpl implements IBookService {
@Autowired
private IBookDao bookDao;
@Autowired
private CacheManager cacheManager;
@Override
public Book queryBookByName(String name) {
return bookDao.queryBookByName(name);
}
@Override
public BookDto queryBookById(Integer id) {
return bookDao.selectById(id);
}
@Override
public Page<Book> getListBooks(BookVo book) {
Page<Book> page = new Page<>(book.getPageNum(), book.getPageSize());
QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
// 设置排序字段
queryWrapper.orderByAsc("publish_date");
// 图书标题不为空时,执行模糊查询
if (null != book.getName() || "".equals(book.getName())){
queryWrapper.like("name",book.getName());
}
return bookDao.selectPage(page,queryWrapper);
}
@Override
public Boolean addBook(Book book) {
Date currentTime = Calendar.getInstance().getTime();
book.setCreateTime(currentTime);
book.setUpdateTime(currentTime);
int rows = bookDao.insert(book);
return rows > 0;
}
@Override
public Boolean editBook(Book book) {
Date currentTime = Calendar.getInstance().getTime();
book.setUpdateTime(currentTime);
int rows = bookDao.updateById(book);
return rows > 0;
}
@Override
public Boolean delBook(Integer id) {
int rows = bookDao.deleteById(id);
return rows > 0;
}
}
5.5 Controller 层
创建com.jhzhong.controller.UserController
、com.jhzhong.controller.BookController
类
// com.jhzhong.controller.UserController
@Controller
@RequestMapping(value = "users")
public class UserController {
@Autowired
private IUserService userService;
@PostMapping(value = "login")
public String login(User user, Model model){
User loginUser = userService.login(user);
model.addAttribute("user", loginUser);
return loginUser != null ? "redirect:/books/list" : "login";
}
@PostMapping(value = "register")
public String register(User user){
Boolean flag = userService.register(user);
return "login";
}
}
// com.jhzhong.controller.BookController
@Controller
@RequestMapping(value = "books")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping(value = "list")
public String queryAllBooks(BookVo book, Model model){
Page<Book> page = bookService.getAllBooks(book);
model.addAttribute("books", page.getRecords());
model.addAttribute("pageInfo", new PageInfo((int) page.getCurrent(), (int) page.getPages(), (int) page.getSize(),page.getTotal()));
return "book_list";
}
@PostMapping(value = "add")
public String addBook(Book book){
Boolean flag = bookService.addBook(book);
return flag ? "redirect:/books/list" : "add";
}
@GetMapping(value = "edit/{id}")
public String toEdit(@PathVariable Integer id, Model model){
BookDto book = bookService.queryBookById(id);
model.addAttribute("book", book);
return "edit";
}
@PostMapping(value = "edit")
public String editBook(Book book){
bookService.editBook(book);
return "redirect:/books/list";
}
@GetMapping(value = "delete/{id}")
public String delBook(@PathVariable Integer id){
Boolean flag = bookService.delBook(id);
return "redirect:/books/list";
}
}
5.6 config 配置类
创建 com.jhzhong.config.MyBatisPlusConfig
类,实现 MybatisPlus 分页拦截器
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
创建com.jhzhong.config.MyMVCConfig
试图管理器类,统一对MVC进行控制
@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index").setViewName("login");
registry.addViewController("/login.html").setViewName("login");
}
}