基于springMVC的图书管理系统

news2024/9/21 11:04:56

进度终于来到了springMVC,下次估计就是springboot了,感觉每次开始新框架,环境都是大问题,项目一共敲四天,环境卡三天。总结一下这次碰到的问题和解决方法吧。

问题和解决方法

1、controller中return无法跳转到界面:

@restController返回数据,@Controller才能跳转界面

还得在springMvcConfig里配置好jsp的类型和位置:

2、报错:找到多个名为spring_web的片段。这是不合法的相对排序。有关详细信息,请参阅Servlet规范的第8.2.2 2c节。考虑使用绝对排序。

听信谗言(不是) 根据百度到的方法在pom.xml里瞎配置,明明已经有springmvc_web了,还是添上了spring_web,直接导致一直报错,解决方法:

在web.xml里加上代码:

<absolute-ordering />

像这样:

3、报错:java.lang.ClassNotFoundException: org.apache.jsp.index_jsp

这个搞得我烦死了,一直找不到原因,包括现在也找不到,所以我的解决方法是新建了一个项目,先把tomcat跑起来,再把代码挪过去,成功解决了。

4、报错:org.springframework.web.bind.MissingServletRequestParameterException: Required Integer parameter 'id' is not present

我代码是这么写的:

后来发现需要用@Param注明参数,像这样,顺利解决:

5、pom.xml中org.apache.maven.plugins标红

找到maven的包存放的位置,找到这个包的版本号,加进去就好了

在setting里找到maven的位置

springMVC中各配置文件作用

1. JdbcConfig

  • 作用: 配置 JDBC 数据源和事务管理。
  • 内容: 通常包括数据库连接信息(如 URL、用户名、密码)以及数据源的 bean 定义。

2. MyBatisConfig

  • 作用: 配置 MyBatis 的相关设置。
  • 内容: 包含 MyBatis 的 SqlSessionFactory、SqlSessionTemplate、Mapper 扫描等配置。

3. ServletConfig

  • 作用: 配置 Servlet 相关的内容。
  • 内容: 定义 DispatcherServlet 的初始化参数和映射 URL,通常用于配置 Spring MVC 的核心功能。

4. SpringConfig

  • 作用: 配置 Spring 的核心功能。
  • 内容: 包含 Bean 的定义、依赖注入、组件扫描等,通常用于管理整个应用程序的 bean 生命周期。

5. SpringMvcConfig

  • 作用: 配置 Spring MVC 的具体设置。
  • 内容: 包含视图解析器、静态资源处理、拦截器等 Spring MVC 特有的配置。

项目介绍

目录

代码

BookController:负责界面的数据获取及更新
package com.example.controller;

import com.example.domain.Book;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

//统一每一个控制器方法返回值
@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookService bookService;

    @PostMapping
    public Result save(@RequestBody Book book) {
        boolean flag = bookService.save(book);
        return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
    }


    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        boolean flag = bookService.delete(id);
        return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
    }

    @PostMapping("/deleteByIds")
    public Result deleteByIds(@RequestParam("ids") List<Integer> ids) {
        boolean flag = bookService.deleteByIds(ids);
        return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR, flag);
    }

    
    @GetMapping
    public Result getAll() {
        List<Book> bookList = bookService.getAll();
        Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
        String msg = bookList != null ? "" : "数据查询失败,请重试!";
        return new Result(code,bookList,msg);
    }

    @GetMapping("/search")
    public Result searchBooks(@RequestParam(value = "bookname", required = false) String bookname,
                              @RequestParam(value = "status", required = false) String status) {
        List<Book> bookList;
        if (bookname == null && status == null) {
            bookList = bookService.getAll(); // 获取所有图书信息
        } else {
            bookList = bookService.getByCondition(bookname, status); // 根据条件查询图书信息
        }
        Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
        String msg = bookList != null ? "" : "数据查询失败,请重试!";
        return new Result(code, bookList, msg);
    }

}
UpdateController:负责界面跳转
package com.example.controller;

import com.example.domain.Book;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

//统一每一个控制器方法返回值
@Controller
@RequestMapping("/update")
public class UpdateController {
    @Autowired
    private BookService bookService;

    @GetMapping("/{id}")
    public String updateBook(@PathVariable("id") Integer id, Model model) {
        Book book = bookService.getById(id);
        model.addAttribute("book", book);
        return "update";
    }

    // 处理修改后提交的表单
    @PostMapping("/{id}")
    public String processUpdateBook(@PathVariable("id") Integer id, @ModelAttribute Book book) {
        System.out.println("processUpdateBook"+id);

        book.setId(id);
        long timestamp = System.currentTimeMillis();
        // 创建SimpleDateFormat对象,并设置日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 将时间戳转换为字符串
        String formattedTimestamp = sdf.format(new Date(timestamp));
        book.setEntry_time(formattedTimestamp);
        bookService.update(book);
        return "redirect:/"; // 修改后重定向到书籍列表页面
    }
    @PostMapping("/changeStatus/{id}/{status}")
    public String updateBookStatus(@PathVariable("id") Integer id,@PathVariable("status") String status) {


        boolean flag = bookService.updateBookStatus(id, status);
        return "redirect:/"; // 修改后重定向到书籍列表页面

    }


}

index.jsp:首页

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<c:set var="pagePath" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
    <jsp:include page="head.jsp">
        <jsp:param value="图书管理系统" name="title" />
    </jsp:include>
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <style>
        .borrowed-book {
            background-color: yellow;
        }
        .navbar {
            text-align: center;
            background: #080808;
            padding: 10px;
        }
        .navbar-buttons a {
            margin: 0 10px;
            text-decoration: none;
            color: #333;
        }
        .search-container {
            text-align: center;
            margin: 20px 0;
        }
        #booksTable {
            width: 100%;
            border-collapse: collapse;
        }
        #booksTable th, #booksTable td {
            border: 1px solid #ddd;
            padding: 8px;
        }
        #booksTable th {
            background-color: #f2f2f2;
        }
        a:link {
            text-decoration: none;
        }
        a:hover {
            color: green;
        }
        .footer {
            text-align: center;
            margin: 20px 0;
            font-size: 18px;
        }
    </style>
</head>
<body>

<div class="navbar">
    <h1 style="margin-right: 1100px;color: #f1f1f1">图书管理系统</h1>
    <div class="navbar-buttons" style="margin-left: 1200px;">
        <a href="add.jsp" style="color: aliceblue">新增图书</a>
        <a href="index.jsp" style="color: aliceblue">返回</a>
    </div>
</div>

<form id="searchForm" action="/books/search" method="get">
    <div class="search-container">
        <input type="text" name="bookname" placeholder="输入图书名进行查询">
        状态:
        <select name="status">
            <option value="可借阅">可借阅</option>
            <option value="已借出">已借出</option>
        </select>
        <input type="submit" value="搜索"/>
    </div>
</form>

<form action="/books/deleteByIds" method="post" id="deleteForm">
    <table id="booksTable" align="center">
        <thead>
        <tr>
            <th><label for="select-all-checkbox">全选</label><input type="checkbox" id="select-all-checkbox" class="select-checkbox"></th>
            <th>序号</th>
            <th>书名</th>
            <th>作者</th>
            <th>出版社</th>
            <th>价格</th>
            <th>状态</th>
            <th>入馆时间</th>
            <th>借阅/归还</th>
<%--            <th>归还</th>--%>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        <c:if test="${not empty books}">
            <c:forEach items="${books}" var="book">
                <tr class="${book.status == '已借出' ? 'borrowed-book' : ''}">
                    <td><input type="checkbox" name="ck" class="select-checkbox" value="${book.id}"/></td>
                    <td>${book.id}</td>
                    <td>${book.bookname}</td>
                    <td>${book.author}</td>
                    <td>${book.introduce}</td>
                    <td>${book.price}</td>
                    <td>${book.status}</td>
                    <td>${book.entry_time}</td>
                    <td>
                        <button type="button" onclick="handleBorrowReturn('${book.id}', '${book.status}')">${book.status == '已借出' ? '归还' : '借阅'}</button>
                    </td>
                    <td>
                        <button><a href="javascript:void(0)" onclick="deleteBook('${book.id}')">删除</a></button>
                        <button><a href="javascript:void(0)" onclick="updateBook('${book.id}')">修改</a></button>
                    </td>
                </tr>
            </c:forEach>
        </c:if>
        </tbody>
    </table>
    <input type="submit" value="批量删除" onclick="return del()">
</form>

<div class="footer">
    图书总数量: <span id="totalBooksCount">${fn:length(books)}</span> 件
</div>

<script>
    $(document).ready(function() {
        $.ajax({
            url: '/books',
            type: 'GET',
            success: function(response) {
                if (response.code === 20041) {
                    updateBooksTable(response.data);
                } else {
                    alert('获取图书列表失败!');
                }
            },
            error: function() {
                alert('获取图书列表失败!请重试!');
            }
        });

        $('#searchForm').submit(function(event) {
            event.preventDefault();
            $.ajax({
                url: '/books/search',
                type: 'GET',
                data: $(this).serialize(),
                success: function(response) {
                    if (response.code === 20041) {
                        const books = response.data;
                        updateBooksTable(books);
                        $('#totalBooksCount').text(books.length);
                    } else {
                        alert('搜索失败!');
                    }
                },
                error: function() {
                    alert('搜索失败,请重试!');
                }
            });
        });

        function updateBooksTable(books) {
            $('#booksTable tbody').empty();
            if (books.length === 0) {
                $('#booksTable tbody').append('<tr><td colspan="10">没有找到图书</td></tr>');
                $('#totalBooksCount').text(0);
                return;
            }
            $.each(books, function(index, book) {
                $('#booksTable tbody').append(
                    `<tr class="${book.status == '已借出' ? 'borrowed-book' : ''}">
                        <td><input type="checkbox" name="ck" class="select-checkbox" value="${book.id}"/></td>
                        <td>${book.id}</td>
                        <td>${book.bookname}</td>
                        <td>${book.author}</td>
                        <td>${book.introduce}</td>
                        <td>${book.price}</td>
                        <td>${book.status}</td>
                        <td>${book.entry_time}</td>
                        <%--<td>--%>
                        <%--    <button type="button" onclick="handleBorrowReturn('${book.id}', '${book.status}','借阅',)">借阅</button>--%>
                        <%--</td>--%>
                        <%--<td>--%>
                        <%--    <button type="button" onclick="handleBorrowReturn('${book.id}', '${book.status}','归还')">归还</button>--%>
                        <%--</td>--%>
                        <td>
                            <button type="button" onclick="handleBorrowReturn('${book.id}', '${book.status}')">${book.status == '已借出' ? '归还' : '借阅'}</button>
                        </td>
                        <td>
                            <button><a href="javascript:void(0)" onclick="deleteBook('${book.id}')">删除</a></button>
                            <button><a href="javascript:void(0)" onclick="updateBook('${book.id}')">修改</a></button>
                        </td>
                    </tr>`
                );
            });
            $('#totalBooksCount').text(books.length);
        }
    });
    function updateBook(bookId) {
        if (confirm('您确定要修改这本书的信息吗?')) {
            window.location.href = '/update/' + bookId; // 注意路径与Controller定义保持一致
        }
    }
    $('#select-all-checkbox').change(function() {
        const isChecked = $(this).is(':checked');
        $('.select-checkbox').prop('checked', isChecked);
    });

    $(document).on('change', '.select-checkbox', function() {
        const allCheckboxes = $('.select-checkbox');
        const allChecked = allCheckboxes.length === allCheckboxes.filter(':checked').length;
        $('#select-all-checkbox').prop('checked', allChecked);
    });

    function deleteBook(bookId) {
        if (confirm('确定要删除这本书吗?')) {
            $.ajax({
                url: '/books/' + bookId,
                type: 'DELETE',
                success: function(response) {
                    if (response.code === 20021) {
                        alert('删除成功!');
                        window.location.href = '';
                    } else {
                        alert('删除失败!');
                    }
                },
                error: function() {
                    alert('删除失败,请重试!');
                }
            });
        }
    }

    function del() {
        const selectedIds = [];
        $('input[name="ck"]:checked').each(function() {
            selectedIds.push($(this).val());
        });

        if (selectedIds.length === 0) {
            alert('请选择要删除的图书!');
            return false;
        }

        if (confirm('确定要删除选中的图书吗?')) {
            $.ajax({
                url: '/books/deleteByIds',
                type: 'POST',
                data: { ids: selectedIds },
                traditional: true,
                success: function(response) {
                    if (response.code === 20021) {
                        alert('批量删除成功!');
                        window.location.href = '';

                        // 重新获取图书数据
                        // loadBooks(); // 删除成功后重新加载图书列表

                    } else {
                        alert('批量删除失败!');
                    }
                },
                error: function() {
                    alert('批量删除失败,请重试!');
                }
            });
        }

        return false;
    }

    function handleBorrowReturn(bookId, currentStatus) {
        let newStatus;
        let action;
        if (currentStatus === '可借阅') {
            newStatus = '已借出';
            action='借阅';
        } else if (currentStatus === '已借出') {
            newStatus = '可借阅';
            action='归还';
        }

        $.ajax({
            url: `/update/changeStatus/${bookId}/${newStatus}`,
            type: 'POST',
            success: function(response) {
                alert(action+'成功!');
                window.location.reload();
            },
            error: function() {
                alert('操作失败,请重试!');
            }
        });

    }
</script>

</body>
</html>

界面

基于springMVC的图书管理系统录屏

整完了,总结完了就可以忘掉这个项目了哈哈哈哈。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1972720.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【安装】Linux Centos 或 Debian 离线安装指定版本MariaDB

【安装】Linux Centos 或 Debian 离线安装指定版本MariaDB 下载地址 https://mariadb.com/downloads/community/community-server/https://mirrors.aliyun.com/mariadb/yum/https://mariadb.com/downloads/community/community-server/ Download MariaDB Server - MariaDB.or…

NineData云原生智能数据管理平台新功能发布|2024年7月版

本月发布 12 项更新&#xff0c;其中性能优化 3 项、功能优化 8 项、安全性发布 1 项。 1. 性能优化 数据复制 - SQL Server 增量性能优化 调整读取和写入方式&#xff0c;让 SQL Server 增量复制的性能轻松达到 5000 RPS 以上。 数据复制 - Doris|SelectDB|StarRocks 性能优…

数据库原理之多表查询——使用Mysql进行内连接和外连接

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 使用环境&#xff1a;Idea 目录 1.内连接 1.1隐式内连接 1.1.1定义 1.1.2举例 1.1.3优缺点 1.2显式内连接 1.2.1定义 1.2.2举例 1.2.3优缺点 2.外连接 2.1左外连接 2.1.1定义 2.1.2举例 2.…

Creomagic 推出认知通信功能以应对电子战 (EW) 威胁

新时代的软件定义无线电 (SDR) 技术可以在电子战和竞争频谱环境中自主维护可靠的网络。 最近的全球冲突凸显了现代战场上战术通信面临的严峻挑战。随着自主部队的日益普及&#xff0c;战场感知变得比以往任何时候都更加先进&#xff0c;需要大量信息传输和同步。在战场上传输关…

【OpenCV C++20 学习笔记】腐蚀和膨胀

腐蚀和膨胀 形态学原理膨胀腐蚀 代码实现膨胀函数腐蚀函数运行结果 形态学原理 腐蚀和膨胀通常有以下用途&#xff1a; 去除噪音分离或合并图像中的元素找出图片上的强度的极大值区域和极小值区域 以下图作为原始图片&#xff1a; 膨胀 用核 B B B来扫描图像 A A A&#xff…

Python数值计算(12)——线性插值

1. 概述 插值是根据已知的数据序列&#xff08;可以理解为你坐标中一系列离散的点&#xff09;&#xff0c;找到其中的规律&#xff0c;然后根据找到的这个规律&#xff0c;来对其中尚未有数据记录的点进行数值估计的方法。最简单直观的一种插值方式是线性插值&#xff0c;它是…

MuseTalk - 数字人唇部同步

文章目录 一、关于 MuseTalk概览新闻模型案例待办事项&#xff1a;第三方集成 二、安装构建环境mmlab 软件包下载 ffmpeg-static下载权重 三、快速入门推理使用 bbox_shift 以获得可调整的结果结合 MuseV 和 MuseTalk&#x1f195;实时推理实时推理注意事项 四、其它致谢限制引…

Taro学习记录

一、安装taro-cli 二、项目文件 三、项目搭建 1、Eslint配置 在项目生成的 .eslintrc 中进行配置 {"extends": ["taro/react"], //一个配置文件&#xff0c;可以被基础配置中的已启用的规则继承"parser": "babel/eslint-parser…

1688中国站获得工厂档案信息 API

公共参数 名称类型必须描述keyString是免费申请调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString否[yes,no]默认y…

【动态规划-最大子段和】力扣1191. K 次串联后最大子数组之和

给定一个整数数组 arr 和一个整数 k &#xff0c;通过重复 k 次来修改数组。 例如&#xff0c;如果 arr [1, 2] &#xff0c; k 3 &#xff0c;那么修改后的数组将是 [1, 2, 1, 2, 1, 2] 。 返回修改后的数组中的最大的子数组之和。注意&#xff0c;子数组长度可以是 0&…

Delphi5实现多窗体

效果图 新建窗体 窗体的显现 procedure TForm2.btn2Click(Sender: TObject); beginForm1.Show;Form2.Hide; end;第一个窗体完整代码 注意引用第二个窗体 unit Unit1;interfaceusesSysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,Dialogs, Forms,Form…

《中国数据库前世今生》观影——2000年代/数据库分型及国产数据库开端

引出 《中国数据库前世今生》观影——2000年代/数据库分型及国产数据库开端 第3集&#xff1a;2000年代/数据库分型及国产数据库开端 y2k问题 千年虫&#xff0c;又叫做“计算机2000年问题”“电脑千禧年千年虫问题”或“千年危机”。缩写为“Y2K]”。是指在某些使用了计算机…

ESP8266 完结日志 2024/8/2 23:50

呼!经历这么长 的时间终于完工了, 从零开始一步一步走过来,还是有一丢丢成就感的 功能: 上传文件 控制引脚 获取信息 重启设备 清空flash 期间接触:web开发 uni-app开发 c开发 python 开发 MQTT AI很棒,棒到我任何问题都想问AI, 甚至一丢丢逻辑下的操作都期盼AI解决. 抖音也…

yolov5的学习part1

还是基础的anoconda&#xff0c;在opencv的时候就已经安装过了 此视频疑似在2020年底录制&#xff0c;因为他安装anaconda使用如下代码 bash ~/Downloads/Anaconda3-2020.07-Linux-x86_64.sh 由于版本兼容问题&#xff0c;可能要mini conda PASCAL VOC PASCAL VOC挑战赛在…

Node.js(6)——npm软件包管理

npm npm是Node.js标准的软件包管理器。 使用&#xff1a; 初始化清单文件&#xff1a;npm init-y(得到package.json文件&#xff0c;有则略过此命令)下载软件包&#xff1a;npm i 软件包名称使用软件包 示例&#xff1a; 初始状态下npm文件夹下只有server.js,下载软件包前看…

揭秘最“硬”的物质,你听说过神秘的“0”号元素吗?

“尽管我们还没有找到它,但这并不意味着它不存在。”——斯蒂芬威廉霍金 亲爱的朋友们,今天我们来探讨一个引人入胜的话题——宇宙中最坚硬的物质是什么?别急,这不是去健身房的邀请,而是一次探索宇宙奥秘的旅程。听说过神秘的“0”号元素吗?让我们一探究竟! 在浩瀚的宇…

unity2D游戏开发12单例

单例 我们先了解一种被称为单例的软件设计模式。当应用程序需要在生命周期内创建特定类的单个实例时,可以使用单例。当一个类提供了游戏中其他几个类使用的功能时,单例会很有用,例如,在Game Manager 类中协调游戏逻辑,单例可以提供对该类及其功能的公共统一访问入口。单例…

C++客户端Qt开发——多线程编程(一)

多线程编程&#xff08;一&#xff09; ①QThread 在Qt中&#xff0c;多线程的处理一般是通过QThread类来实现。 QThread代表一个在应用程序中可以独立控制的线程&#xff0c;也可以和进程中的其他线程共享数据。 QThread对象管理程序中的一个控制线程。 run() 线程的入口…

用Python插入表格到PowerPoint演示文稿

有效的信息传达是演示文稿中的重点&#xff0c;而PowerPoint演示文稿作为最广泛使用的演示工具之一&#xff0c;提供了丰富的功能来帮助演讲者实现这一目标。其中&#xff0c;在演示文稿中插入表格可以帮助观众更直观地理解数据和比较信息。通过使用Python这样的强大编程语言&a…

前端优化之图片的渐进式加载

起因&#xff1a; 在访问自己部署的前端项目的时候发现&#xff0c;背景图片加载太慢&#xff0c;并不是很美观。 这是因为&#xff0c;除了 JavaScript 和 CSS&#xff0c;网站通常还会包含大量的图片。当自己把<img> 元素添加到网站里面时&#xff0c;对应的所有图片…