First assignment __ A_simple_Library_Book_Management_System_832201310_ZongshengLi

832201310李宗晟 2024-10-28 12:30:03

0. A__simple__Diction_Table 

1. Introduction ( Including intention and simple project contents intro and project getting approaches )

  1.1. Intention

  1.2. Simple project contents ( Including the Requiremnts Analysis )

  1.3. How to get the Project 

2. PSP Table

3. Codes Specification and Front-end and back-end Separation Demonstration

  3.1. Front-end WebPage Connection Demostration ( Including Login Page and Function Page )

  3.2. Back-end Datebase Building Demostration 

  3.3 Datebase Contents Presentation ( Interactive Dates and Blocks )

4. Some small Thoughts on the project


1. Introduction

1.1. Intention

This project aims to develop a web-based book lending and return management system with a front-end and back-end separation architecture. It is designed to assist those who have a need for software front-end and back-end separation, have a basic understanding of the Vue and Spring Boot development frameworks, and want to create a functional web page management system.

1.2. Simple project contents

Account Management

  • User Registration:
    • Users should be able to create new accounts through a registration form.
    • The form should collect necessary information such as username, password, and perhaps additional user details like name, email address, etc.
  • Account Authentication:
    • Implement a secure authentication mechanism to ensure that only registered users can access the system.
    • This may involve password hashing and session management to maintain user login sessions.

Book Lending and Return Information Management

  • Create, Read, Update, Delete (CRUD) Operations:
    • Create: Administrators should be able to add new book lending and return records to the system. This includes details such as the book ID, borrower ID, lending date, return date (if applicable), and any other relevant information.
    • Read: Both administrators and users (readers) should be able to view the book lending and return information. The information should be presented in a clear and organized manner, preferably in a table format.
    • Update: Administrators should be able to modify existing lending and return records. For example, if a return date is changed or additional information needs to be updated.
    • Delete: Administrators should have the ability to delete incorrect or obsolete lending and return records.
  • Search Bar
    • Implement a search bar functionality that allows readers to search for books by title.
    • When a book title is entered, the system should display the status information of the book, including whether it is "In the library", "Lost", or "Lent out".

1.3. How to get the project

NameGithub Address
Front-end of the ProjectZongshengLi3011/Inc: Library Book Management System
Back-end of the ProjectInc/front-end at main · ZongshengLi3011/Inc

 

 

 

 


2. PSP Table

PSP PhaseTask DescribeEstimated Cost Time (minutes)Actual Cost Time (minutes)
PlanningRequirements Analysis3015
Development Analysis3010
DesignInterface Design1030
Demo Datebase Design1520
Controller Design1530
CodingBack-end Coding60120
Front-end Coding6030
TestDebug180120
Requirements Achievement1010
Secondary optimization of code1010
SummaryRecord processing details and troubles1010
Total370 405

 

 

 

 

 

 

 

 

 

 

 

 

 


3. Codes Demo and Front-end and back-end Separation Demonstration

3.1. Front-end WebPage Connection Demostration ( Including Login Page and Function Page )

Main API

Code Function Overview

 Codes mainly builds an encapsulation module for HTTP requests based on the axios library, which is used to handle the interaction with the backend API in a Vue project (inferred from the import paths in the code). It implements the following functions:

  1. Set global axios configuration:
    • Set withCredentials to true, which is used to carry cookies during cross - domain requests.
    • (Some commented - out code) Originally might be used to set the Authorization header and the Content - Type header (for POST requests).
  2. Request and response interceptors:
    • Request interceptor: Before each request is sent, if there is an access - token in local storage, it is added to the Authorization field of the request header, and the loading state of the application (presumably for showing a loading animation or similar functionality) is set to true.
    • Response interceptor: After receiving a response, the loading state is set to false. Processing is based on the code value in the response data:
      • If the code is 401, trigger a jump to the /login page via the event bus bus (possibly for the case of not being logged in).
      • If the code is 402, display an error message for login expiration and trigger a jump to the /login page via the event bus bus.
  3. HTTP method encapsulation:
    • Defines methods such as POSTPOSTFORMGETPUTDELETEPATCH. These methods are encapsulated based on the corresponding request methods of axios, uniformly set the base address of the request (base), and return the response data (through .then(res => res.data)).

Code Detail Analysis

  • axios configuration - related:

    • During cross - domain requests, this allows the browser to include cookies in the request, which is important for scenarios involving authentication that require cookies.

    • The commented - out axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; and axios.defaults.headers.post['Content - Type'] = 'application/x - www - form - urlencoded;charset=UTF - 8'; parts, if AUTH_TOKEN is defined, were originally used to globally set the authentication information in the request header and the Content - Type of POST requests.

  • Request interceptor part:

    • In axios.interceptors.request.use:

      • Checks if an access - token exists in local storage. If it does, it is added to the request header for backend authentication.

      • Updates the loading state in the store, which may be associated with a loading indicator on the UI to inform the user that a request is in progress.

  • Response interceptor part:

    • In axios.interceptors.response.use:

      • After the request is completed, regardless of success or failure, the loading state is set to false to hide the loading indicator.

      • Processing based on the value of response.data.code:

        • For error codes 401 and 402, operations to jump to the login page are triggered respectively. In the case of 402, an error message is also displayed to the user.

  • HTTP method encapsulation part:

    • POST method:

      • It accepts url and params parameters, uses the post method of axios to send a request. The request address is the concatenation of base (base address) and url, and the request parameter is params. Finally, it returns the response data.

    • POSTFORM method:

      • Similar to POST, but an additional request header Content - Type is set to multipart/form - data, which is used for handling form data uploads and other situations that require a special Content - Type.

    • GET method:

      • Uses the get method of axios and adds params as query parameters to the url.

    • PUTDELETEPATCH methods: Similar to POST, they use the corresponding PUTDELETEPATCH methods of axios respectively to implement the corresponding HTTP request functions.

import axios from 'axios'
import store from "../vuex/store";
import { Message } from 'element-ui';
import {
  bus
} from '../bus.js'

axios.defaults.withCredentials = true;
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
//  axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';//配置请求头


//添加一个请求拦截器
axios.interceptors.request.use(
  config => {
    if (window.localStorage.getItem('access-token')) {
      config.headers.Authorization = window.localStorage.getItem('access-token');
    }
    store.state.loading = true
    return config
  },
  error => {
    return Promise.reject(error)
  }
);
// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
  store.state.loading = false
  if (response.data && response.data.code) {
    const resCode = parseInt(response.data.code);
    if (resCode === 401) {
      //未登录
      bus.$emit('goto', '/login')
    }

    if (resCode === '402') {
      //登录过期
      Message.error({
        showClose: true,
        message: '登录过期,请重新登录',
        duration: 2000
      });

      bus.$emit('goto', '/login')
    }
  }

  return response;
}, function (error) {
  store.state.loading = false
  // Do something with response error
  return Promise.reject(error);
});

//基地址
let base = process.env.API_ROOT


//通用方法
export const POST = (url, params) => {
  return axios.post(`${base}${url}`, params).then(res => res.data)
}

//表单方法
export const POSTFORM = (url, params) => {
  const config ={headers:{"Content-Type":"multipart/form-data"}}
  return axios.post(`${base}${url}`, params, config).then(res => res.data)
}

export const GET = (url, params) => {
  return axios.get(`${base}${url}`, {
    params: params
  }).then(res => res.data)
}

export const PUT = (url, params) => {
  return axios.put(`${base}${url}`, params).then(res => res.data)
}

export const DELETE = (url, params) => {
  return axios.delete(`${base}${url}`, {
    params: params
  }).then(res => res.data)
}

export const PATCH = (url, params) => {
  return axios.patch(`${base}${url}`, params).then(res => res.data)
}

Route Structure                                                                                                                           

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/view/Home'
import Dashboard from '@/view/Dashboard'
import Index from '@/view/welcome/index.vue'
import BookList from '@/view/role/list'
import UserList from '@/view/user/list'
import UserChangePwd from '@/view/user/changepwd'
import UserProfile from '@/view/user/profile'
import MenuList from '@/view/menu/list'
import Book from '@/view/book/list'


// 懒加载方式,当路由被访问的时候才加载对应组件
const Login = resolve => require(['@/view/Login'], resolve)

Vue.use(Router)

let router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/index',
      name: '首页',
      component: Index
    },
    {
      path: '/login',
      name: '登录',
      component: Login
    },
    {
      path: '/',
      name: 'home',
      component: Home,
      redirect: '/dashboard',
      leaf: true, // 只有一个节点
      menuShow: true,
      iconCls: 'fa fa-home', // 图标样式class
      children: [
        {path: '/dashboard', component: Dashboard, name: '首页', menuShow: true}
      ]
    },
    {
      path: '/',
      component: Home,
      name: '用户管理',
      menuShow: true,
      leaf: true, // 只有一个节点
      iconCls: 'fa fa-user', // 图标样式class
      children: [
        {path: '/admin/user', component: UserList, name: '用户列表', menuShow: true}
      ]
    },
    {
      path: '/',
      component: Home,
      name: '图书管理',
      menuShow: true,
      leaf: true, // 只有一个节点
      iconCls: 'fa fa-user', // 图标样式class
      children: [
        {path: '/book', component: Book, name: '图书列表', menuShow: true}
      ]
    },
    {
      path: '/',
      component: Home,
      name: '菜单管理',
      menuShow: true,
      leaf: true, // 只有一个节点
      iconCls: 'fa fa-server', // 图标样式class
      children: [
        {path: '/admin/menu', component: MenuList, name: '菜单列表', menuShow: true}
      ]
    },
    {
      path: '/',
      component: Home,
      name: '角色管理',
      menuShow: true,
      leaf: true,
      iconCls: 'fa fa-group',
      children: [
        {path: '/admin/role', component: BookList, name: '角色管理', menuShow: true},
      ]
    },

    {
      path: '/',
      component: Home,
      name: '文件管理',
      menuShow: true,
      leaf: true,
      iconCls: 'fa fa-group',
      children: [
        {path: '/cms/file', component: FileList, name: '文件管理', menuShow: true},
      ]
    },
    {
      path: '/',
      component: Home,
      name: '设置',
      menuShow: true,
      iconCls: 'iconfont icon-setting1',
      children: [
        {path: '/user/profile', component: UserProfile, name: '个人信息', menuShow: true},
        {path: '/user/changepwd', component: UserChangePwd, name: '修改密码', menuShow: true}
      ]
    },
  ]
})

router.beforeEach((to, from, next) => {
  if (to.path.startsWith('/login')) {
    window.localStorage.removeItem('access-token')
    //window.localStorage.removeItem('access-user')
    next()
  } else if (to.path.startsWith('/index')) {
    next()
  } else {
    //let user = JSON.parse(window.localStorage.getItem('access-token'))
    let user = window.localStorage.getItem('access-token');
    if (!user) {
      next({path: '/login'})
    } else {
      next()
    }
  }
})

export default router

 Some Demos

Post Page: https://www.bilibili.com/video/BV1yF1GYhE1G/?spm_id_from=333.999.0.0

Page Function: https://www.bilibili.com/video/BV1WF1GYhEXn/?spm_id_from=333.999.0.0

3.2. Back-end Datebase Building Demostration 

Some parts of Controllers

package com.inc.admin.controller.biz;

import com.inc.admin.domain.biz.Book;
import com.inc.admin.service.biz.BookService;
import com.inc.admin.utils.R;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/book")
public class BookController {
    @Resource
    private BookService bookService;

    /**
     * 分页查询 图书列表
     */
    @PostMapping("/listByPage")
    public R listByPage(@RequestBody Book req) {
        return R.ok().put("page", bookService.listByPage(req));
    }

    /**
     * 添加 图书信息
     */
    @PostMapping("/insert")
    public R insert(@RequestBody Book req) {
        return R.operate(bookService.insert(req)>0);
    }

    /**
     * 更新 图书信息
     */
    @PostMapping("/update")
    public R update(@RequestBody Book req) {
        return R.operate(bookService.update(req)>0);
    }

    /**
     * 删除 图书信息
     */
    @PostMapping("/delete")
    public R delete(@Validated @NotNull(message = "编号不能为空") @RequestParam("id") @RequestBody Integer id) {
        return R.operate(bookService.delete(id)>0);
    }
}

Login Controller

package com.inc.admin.controller.sys;

import com.inc.admin.domain.sys.UserDO;
import com.inc.admin.dto.sys.UserDTO;
import com.inc.admin.dto.sys.req.UpPwdReq;
import com.inc.admin.service.sys.RoleService;
import com.inc.admin.service.sys.UserService;
import com.inc.admin.utils.MD5Utils;
import com.inc.admin.context.FilterContextHandler;
import com.inc.admin.dto.sys.LoginUserDTO;
import com.inc.admin.utils.ObjectCopyUtils;
import com.inc.admin.utils.PageUtils;
import com.inc.admin.utils.Query;
import com.inc.admin.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequestMapping("/user")
@RestController
public class UserController extends BaseController {
    @Autowired
    UserService userService;
    @Autowired
    RoleService roleService;

	/**
	 * 登录的当前用户,前台需要验证用户登录的页面可以调用此方法
	 * @return
	 */
    @GetMapping("/currentUser")
    LoginUserDTO currentUser(){
		LoginUserDTO loginUserDTO = new LoginUserDTO();
		loginUserDTO.setUserId(FilterContextHandler.getUserID());
		loginUserDTO.setUsername(FilterContextHandler.getUsername());
		loginUserDTO.setName(FilterContextHandler.getName());
		return loginUserDTO;
	}

	/**
	 * 根据用户id获取用户
	 * @param id
	 * @return
	 */
    @GetMapping("{id}")
	R get(@PathVariable("id") Long id ){
		UserDO userDO = userService.get(id);
    	return R.ok().put("data", ObjectCopyUtils.copyProperties(new UserDTO(), userDO));
	}

	/**
	 * 分页查询用户
	 * @param params
	 * @return
	 */
    @GetMapping()
    R listByPage(@RequestParam Map<String, Object> params) {
        Query query = new Query(params);
		List<UserDO> list = userService.list(query);
		List<UserDTO> userDTOS = ObjectCopyUtils.copyListProperty(UserDTO.class, list);
        int total = userService.count(query);
        PageUtils pageUtil = new PageUtils(userDTOS, total);
        return R.ok().put("page",pageUtil);
    }

	/**
	 * 增加用户
	 * @param user
	 * @return
	 */
	@PostMapping()
    R save(@RequestBody UserDO user) {
		if (exits(user.getUsername())) {
			return R.error("用户名已存在");
		}
		user.setPassword(MD5Utils.encrypt(user.getUsername(), user.getPassword()));
		return R.operate(userService.save(user) > 0);
	}

	@PostMapping("register")
    R register(@RequestBody UserDO user) {
		if (exits(user.getUsername())) {
			return R.error("用户名已被注册");
		}
		user.setroleIds(Arrays.asList(56L));
		user.setPassword(MD5Utils.encrypt(user.getUsername(), user.getPassword()));
		return R.operate(userService.save(user) > 0);
	}

	@PostMapping("resetPwd")
    R resetPwd(@RequestBody UserDO user) {
		return userService.resetPwd(user.getUserId());
	}

	@PostMapping("updatePwd")
    R updatePwd(@RequestBody @Validated UpPwdReq req) {
		return userService.updatePwd(req);
	}

	/**
	 * 修改用户
	 * @param user
	 * @return
	 */
	@PutMapping()
	R update(@RequestBody UserDO user) {
		return R.operate(userService.update(user) > 0);
	}

	@PostMapping("profile")
	R profile(@RequestBody UserDO user) {
		user.setUserId(Long.parseLong(FilterContextHandler.getUserID()));
		return R.operate(userService.profile(user)>0);
	}

	/**
	 * 删除用户
	 * @param id
	 * @return
	 */
	@DeleteMapping()
	R remove( Long id) {
		return R.operate (userService.remove(id) > 0);
	}

	@PostMapping("/batchRemove")
	@ResponseBody
	R batchRemove(@RequestParam("ids[]") Long[] userIds) {
		int r = userService.batchremove(userIds);
		if (r > 0) {
			return R.ok();
		}
		return R.error();
	}

	boolean exits(String userName) {
		// 存在,不通过,false
		Map<String, Object> params = new HashMap<>();
		params.put("username", userName);
		return userService.exits(params);
	}
}

Some Demos

Backend Post Buildup: https://www.bilibili.com/video/BV1sF1GYhEm3/

 

3.3 Datebase Contents Presentation ( Interactive Dates and Blocks )

Some Demos

Frontend: https://www.bilibili.com/video/BV1WF1GYhEXg/

Backend: https://www.bilibili.com/video/BV1sF1GYhEz7/

 

4. Some small Thoughts on the project

The development of front-end and back-end separation projects includes planning requirements, technology selection and architecture design. The front - end builds the environment, develops page components and state management, and conducts tests. The back - end builds the environment, designs models and databases, develops interfaces, implements business logic, and conducts tests. Then, front - end and back - end integration and joint debugging are carried out, and optimization and adjustment are made through configuring cross - domain access and joint debugging of interfaces. For a person who has no foundation in software engineering projects at all, learning this entire project is really like opening the door to a new world.

...全文
188 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

174

社区成员

发帖
与我相关
我的任务
社区描述
2401_MU_SE_FZU
软件工程 高校
社区管理员
  • FZU_SE_TeacherL
  • 助教-吴可仪
  • 助教-孔志豪
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧