进度终于来到了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的图书管理系统录屏
整完了,总结完了就可以忘掉这个项目了哈哈哈哈。