基于SpringBoot和MySQL的图书管理系统
1.前言
该图书管理系统是基于SpringBoot的项目,希望能够和小伙伴们一起学习,得到宝贵的意见。
2.项目介绍
2.1 功能简介
系统分管理员界面与用户界面,基于SpringBoot 的图书管理系统,主要包括系统管理、图书管理、借阅者管理三部分。
-
管理员 :实现对图书的增、删、改、查,对所有借阅历史的搜索及所有账户的信息,用户的权限与管理,设定密码,借阅图书及对自己账户的资料修改
-
用户 :实现对图书的借阅功能、查看自己的借阅历史,在用户账户方面实现修改密码以及修改个人信息功能
2.2 功能模块图
2.3 组织结构
├─src
│ ├─main
│ │ ├─java
│ │ │ └─io
│ │ │ └─mvc
│ │ │ └─web
│ │ │ └─book
│ │ │ ├─annotation 自定义注解类
│ │ │ ├─common 公共类
│ │ │ ├─config 配置类
│ │ │ ├─controller 控制层
│ │ │ ├─dao dao层接口
│ │ │ ├─exception 全局统一异常处理
│ │ │ ├─interceptor 过滤接口
│ │ │ ├─model 实体类
│ │ │ ├─service 业务层
│ │ │ │ └─impl 实现类
│ │ │ └─util 工具类
│ │ ├─resources
│ │ │ └─mapper dao层对应mapper文件
│ │ └─webapp
│ │ ├─static 静态资源文件
│ │ └─WEB-INF
│ │ └─page jsp文件
│ │ ├─admin 管理员
│ │ └─common 普通用户
2.4 技术栈
2.5 开发环境
-
JDK(1.8+)
-
Maven (3.6.0+)
-
MySQL (5.6+)
-
IDEA(2019.3)
3.数据库设计
3.1 表结构
用户表
权限表
权限&用户表
菜单表
权限&菜单表
还书表
图书类型表
图书信息表
3.2 E-R图
4.项目开发
4.1 常用工具类
加密类
```java public class Md5Util {
public static final String SALT = "Book";
public static String md5(String str, String salt) {
if (StringUtils.isEmpty(str)) {
return null;
} else {
return new Md5Hash(str, salt).toString();
}
}
//测试调用
public static void main(String args[]) {
String password = "123456";
System.out.println("Md5加密后" + Md5Util.md5(password, Md5Util.SALT));
}
} ```
JWT 安全校验类
```java public class JwtUtil {
//签发者
public static final String ISSUER = "曾冯周。-";
//公钥
public static final String SECRET = "zengfengzhou";
public static String createToken(User user) {
// 签发时间
Date iatDate = new Date();
// 过期时间
Calendar nowTime = Calendar.getInstance();
nowTime.add(Calendar.MINUTE, 120);
Date expiresDate = nowTime.getTime();
// header
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
String token = JWT.create()
.withHeader(map)
.withIssuer(JwtUtil.ISSUER)
.withAudience(Long.toString(user.getUserId()))//接收者
.withExpiresAt(expiresDate)
.withIssuedAt(iatDate)
.sign(Algorithm.HMAC256(JwtUtil.SECRET));
return token;
}
public static String getUserId(String token) {
String userId;
DecodedJWT jwt = JWT.decode(token);
userId = jwt.getAudience().get(0);
return userId;
}
public static void main(String args[]) {
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxIiwiaXNzIjoi6IKG5oSP44CCLSIsImV4cCI6MTU1MjQzNjIwMywiaWF0IjoxNTUyNDM0NDAzfQ.rtpYANOHZE_tpkF0ChWsLOHMrdmWETjg2SVX3wjr6OQ";
System.out.println(JwtUtil.getUserId(token));
}
} ```
随机数字类
```java public class IDUtils { /* * 生成用户ID(同时作为借书证编号) * @return / public static long genUserId() { //取当前时间的长整形值包含毫秒 long millis = System.currentTimeMillis(); //long millis = System.nanoTime(); //加上两位随机数 Random random = new Random(); int end2 = random.nextInt(99); //如果不足两位前面补0 String str = millis + String.format("%02d", end2); long id = new Long(str); return id; }
public static void main(String[] args) {
for (int i = 0; i < 100; i++)
System.out.println(genUserId());
}
} ```
4.2 登陆拦截器实现
```java public class LoginInterceptor implements HandlerInterceptor { @Resource private UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查是否有passtoken注解,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
//检查有没有需要用户登录的注解
User currentUser = (User) httpServletRequest.getSession().getAttribute("user");
if (method.isAnnotationPresent(LoginRequired.class)) {
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
if (loginRequired.required()) {
if (currentUser == null) {
httpServletResponse.sendRedirect("/login.jsp");
return false;
}
}
}
//检查有没有需要用户token的注解
String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
if (method.isAnnotationPresent(UserLoginToken.class)) {
UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
if (userLoginToken.required()) {
// 执行认证
if (token == null) {
throw new RuntimeException("token为空,请重新登录");
}
// 获取 token 中的 user id
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("无权限访问");
}
User user = userService.findUserByUserId(Long.parseLong(userId));
if (user == null) {
throw new RuntimeException("用户不存在,请重新登录");
}
// 验证 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JwtUtil.SECRET)).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("token失效,无权限访问");
}
return true;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
} ```
4.3 全局异常处理
```java /* * @Description:统一处理一个Controller中抛出的异常 /
@RestControllerAdvice public class AjaxExceptionHandler {
@ExceptionHandler(value = Exception.class)
public JsonData defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
e.printStackTrace();
return JsonData.fail(e.getMessage());
}
/**
* 注解参数校验 全局异常补获
*/
@ExceptionHandler(BindException.class)
public JsonData handleBindException(BindException ex) {
//校验 除了 requestbody 注解方式的参数校验 对应的 bindingresult 为 BeanPropertyBindingResult
FieldError fieldError = ex.getBindingResult().getFieldError();
return JsonData.fail(fieldError.getDefaultMessage());
}
} ```
4.4 登录校验
```java @PostMapping("/login") public JsonData login(@RequestParam(value = "userName") String userName, @RequestParam(value = "userPassword") String userPassword, @RequestParam(value = "vaptchaToken") String vaptchaToken, HttpServletRequest request, HttpSession session) throws Exception {
if (StringUtils.isEmpty(userName)) {
return JsonData.fail("用户名不能为空!");
}
if (StringUtils.isEmpty(userPassword)) {
return JsonData.fail("密码不能为空!");
}
User user = userService.findUserByUserName(userName);
if (user == null) {
return JsonData.fail("用户不存在!");
}
if (user.getUserState() == 0) {
return JsonData.fail("账号已被禁用!请联系管理员!");
}
if (Md5Util.md5(userPassword, Md5Util.SALT).equals(user.getUserPassword())) {
//获取用户角色信息
List<Role> roleList = roleService.findByUserId(user.getUserId());
StringBuffer stringBuffer = new StringBuffer();
for (Role role : roleList) {
stringBuffer.append("," + role.getRoleName());
}
user.setRoles(stringBuffer.toString().replaceFirst(",", ""));
session.setAttribute("user", user);
//获取用户权限信息
List<Permission> permissions = permissionService.queryPermissionsByUser(user);
Map<Integer, Permission> permissionMap = new HashMap<>();
Permission root = null;
Set<String> uriSet = new HashSet<>();
for (Permission permission : permissions) {
permissionMap.put(permission.getPermissionId(), permission);
if (permission.getPermissionUrl() != null && !"".equals(permission.getPermissionUrl())) {
uriSet.add(permission.getPermissionUrl());
}
}
session.setAttribute("authUriSet", uriSet);
for (Permission permission : permissions) {
Permission child = permission;
if (child.getPermissionParentId() == null) {
root = permission;
} else {
Permission parent = permissionMap.get(child.getPermissionParentId());
parent.getChildren().add(child);
}
}
session.setAttribute("rootPermission", root);
return JsonData.success();
} else {
return JsonData.fail("用户名或密码错误!");
}
}
```
4.5 借阅功能实现
```java @RestController @RequestMapping("/book") public class LendBookController { @Resource private LendBookService lendBookService; @Resource private BookInfoService bookInfoService; @Resource private UserService userService;
@PostMapping("/lendBook")
@LoginRequired
public JsonData lendBook(LendReturnList lendReturnList) throws ParseException {
User user = userService.findUserByUserId(lendReturnList.getUserId());
if (user == null) {
return JsonData.fail("用户不存在");
}
if (user.getUserState() == 0) {
return JsonData.fail("用户已被禁用,无法借阅");
}
BookInfo info = bookInfoService.selectBookInfoById(lendReturnList.getBookId());
if (info == null) {
return JsonData.fail("图书不存在");
}
if (info.getBookState() == 1) {
return JsonData.fail("图书已被借出,无法借阅");
}
int i = lendBookService.lendBook(lendReturnList);
//更新图书状态为借出
BookInfo bookInfo = BookInfo.builder()
.bookId(lendReturnList.getBookId())
.bookState(1).build();
bookInfoService.updateBookInfo(bookInfo);
if (i > 0) {
return JsonData.success(i, "借阅成功");
} else {
return JsonData.fail("借阅失败");
}
}
/**
* @description: 根据用户ID查询借还记录
*/
@PostMapping("/lendreturnrecord")
@LoginRequired
public DataGridDataSource<LendReturnList> selectLendReturnRecordByUserId(@RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
@RequestParam(value = "rows", required = false, defaultValue = "5") Integer rows,
HttpSession session) throws ParseException {
User currentUser = (User) session.getAttribute("user");
PageBean pageBean = new PageBean(page, rows);
Map<String, Object> map = new HashMap<>();
map.put("userId", currentUser.getUserId());
map.put("start", pageBean.getStart());
map.put("size", pageBean.getPageSize());
List<LendReturnList> lendReturnLists = lendBookService.selectLendReturnRecordByUserId(map);
int totalRecord = lendBookService.getTotalRecord(map);
DataGridDataSource<LendReturnList> list = new DataGridDataSource<>();
list.setTotal(totalRecord);
list.setRows(lendReturnLists);
return list;
}
} ```
4.6 权限校验
```java @RestController @RequestMapping("/role") public class RoleController { @Resource private RoleService roleService; @Resource private PermissionService permissionService; /* * @description: 新增角色 / @PostMapping("/save") @LoginRequired public JsonData saveRole(Role role) { int count = roleService.saveRole(role); if (count > 0) { return JsonData.success(count, "添加成功"); } else { return JsonData.fail("添加失败"); }
}
/**
* @description: 更新角色
*/
@PutMapping("/update")
@LoginRequired
public JsonData updateRole(Role role) {
int count = roleService.updateRole(role);
if (count > 0) {
return JsonData.success(count, "更新成功");
} else {
return JsonData.fail("更新失败");
}
}
/**
* @description: 删除角色(先根据角色id删除角色权限关联信息, 再根据角色id删除用户角色关联信息)
*/
@DeleteMapping("/delete")
@LoginRequired
public JsonData deleteRole(@RequestParam(value = "roleId") Integer roleId) {
//TODO 根据角色id删除角色权限关联信息,再根据角色id删除用户角色关联信息
permissionService.deleteRolePermissionRsByRoleId(roleId);
roleService.deleteRoleUserRsByRoleId(roleId);
int count = roleService.deleteRole(roleId);
if (count > 0) {
return JsonData.success(count, "删除成功");
} else {
return JsonData.fail("删除失败");
}
}
/**
* @description: 服务端分页查询角色列表
*/
@PostMapping("/list")
@LoginRequired
public DataGridDataSource<Role> getRoleList(@RequestParam(value = "roleName", required = false, defaultValue = "") String roleName,
@RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
@RequestParam(value = "rows", required = false, defaultValue = "5") Integer rows) {
PageBean pageBean = new PageBean(page, rows);
Map<String, Object> map = new HashMap<>();
map.put("roleName", "%" + roleName + "%");
map.put("start", pageBean.getStart());
map.put("size", pageBean.getPageSize());
List<Role> roleList = roleService.selectRoleList(map);
int totalRole = roleService.getTotalRole(map);
DataGridDataSource<Role> dataGridDataSource = new DataGridDataSource<>();
dataGridDataSource.setRows(roleList);
dataGridDataSource.setTotal(totalRole);
return dataGridDataSource;
}
/**
* @description: 角色权限设置(先删除当前角色拥有的权限关系, 再重新设置)
*/
@PostMapping("/savePermissionSet")
@LoginRequired
public JsonData savePermissionSet(Integer roleId, Integer[] permissionIds) {
//先删除当前角色拥有的权限关系
permissionService.deleteRolePermissionRsByRoleId(roleId);
Map<String, Object> map = new HashMap<>();
map.put("roleId", roleId);
map.put("permissionIds", permissionIds);
int count = roleService.insertRolePermissions(map);
if (count > 0) {
return JsonData.success(count, "设置成功");
} else {
return JsonData.fail("设置失败");
}
}
} ```
5.项目展示
5.1 借阅者
登录页
首页
还书
图书检索
借还记录
修改密码
5.2 管理员
首页(用户管理)
分配权限
角色管理
菜单管理
5.3 图书管理
分类管理
图书信息管理
借书管理
还书管理
6.总结
首先,恭喜自己(伪)独立完成了一个后台的图书管理系统。
在这一过程中,我最主要的问题是——呃,什么都不会!
没错,真的是什么都不会。一个月前,我所拥有的对这个项目唯一有帮助的基础是:使用eclipse自学过两周java编程算法。除此之外,没有任何web项目经验,没有任何spring经验,没有任何J2EE经验。在学校里只学过c++,而且仅限于算法。
老实说,当我面对这个项目命题时,我感到了深深的绝望和对以往荒废时光的惋惜。于是,我开始做的第一件事就是,登录b站,打开点击最高的spring,springmvc,mybatis,springboot视频。。。。。
咳咳,闲话扯远了,回到正题!
这篇博客我将尽可能完整地展示一个springboot系统的构建思路和业务逻辑。当然,项目还存在一些不够友好的bug,以及功能单薄的缺点(可我实在懒得改了)。博客的发布,最主要目的是我对过去一个月的思考和知识的巩固汇总,所以不会一一列举所有的项目内容(比如对对象的增删改查操作等),尤其是我自己觉得很简单的部分,所以可能会显得不够全面,如果你需要全面的代码,那么可以去git上搜索靠前的原码。
那么问题来了,依靠这篇博客你可以成功完成一个项目吗?
答案显然是no。因为我只是总结一些个人在项目中遇到的重点,我自己本身也是通过视频,博客,git等途径逐步学习完成的整个项目。也就是说,这不是一篇教学类的博客。
如果你要完成一个自己的项目,你需要看更多的视频,学更多的基础知识,看更多的博客,这只是一个参考,并且不一定是你能用到的参考。仅此。
基本来说,我将采取每天(???)更新的方式,逐步完成。
参考文献
- 基于SSH框架的图书馆管理系统的设计与实现(山东大学·檀雪姣)
- 基于JSP的图书管理系统的需求分析与设计(山东大学·杜鹏)
- 基于.NET的图书管理系统的设计与实现(安徽大学·陈龙)
- 基于JSP的图书馆管理系统的设计与实现(吉林大学·葛再立)
- 基于SSH框架的图书馆管理系统分析与设计(云南大学·郑晨)
- 基于B/S架构的图书管理系统的设计与实现(山东大学·蒲琼)
- 基于B/S架构的图书管理系统的设计与实现(山东大学·蒲琼)
- 基于RBAC的SSH架构下的图书管理应用研究(大连理工大学·姜楠)
- 石化职业技术学院图书馆管理系统设计与实现(西安电子科技大学·县伟)
- 基于RBAC的SSH架构下的图书管理应用研究(大连理工大学·姜楠)
- 基于B/S架构的图书管理系统设计与实现(西安电子科技大学·龚玉)
- 基于Spring架构的职业学院图书馆管理系统的构建(复旦大学·吕晶)
- 基于.NET的图书管理系统的设计与实现(安徽大学·陈龙)
- 基于B/S架构的网上书店系统的设计与实现(电子科技大学·陈云英)
- 基于SSH框架的图书馆管理系统分析与设计(云南大学·郑晨)
本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:代码驿站 ,原文地址:https://m.bishedaima.com/yuanma/35465.html