目录
我有话说:
1 项目简介
2 项目展示
2.1 首先创建数据库和表信息
2.2 预先准备操作
2.3 开始配置项目
2.4 开始web层
3 图片展示
4 附上源码文件(百度网盘):
- 首先 内容比较多,篇幅比较长,有需要的可以耐心看完.
- 这个项目最开始是跟着狂神写下来的,附上狂神的详细视频链接及详细笔记:
17、ssm整合:Mybatis层_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1aE41167Tu?p=17&vd_source=b1036c3d2e010aa91f6ccb4fed6293ec狂神SSM教程- 专栏 -KuangStudyhttps://www.kuangstudy.com/zl/ssm#1377532368339955713
"如果没有SSM框架的基础,建议先学完SSM的基础知识,这样听起来会容易很多".
- 跟着狂神写项目的期间没有遇到报错,但是写完之后觉得如果只是这样我并不满足,所以把我会的内容基本上都在这个项目中写出来了,我认为这是我的一种进步.
- 正常来说一个项目从开始到结束应该是一步一步来的,这里因为时间问题,无法一步一步展示.
- 虽然内容是整个项目的,但是建议还是再纯手打一遍,因为复制粘贴总会有些不必要的问题,哪怕正确的代码,复制粘贴可能还是有问题.
- 项目中的jsp页面可以先用vscode写一遍然后复制到jsp页面即可.
- 所谓框架,就是搭好一个架子,然后所有的操作都在框架的内部进行,不需要对框架进行其他的修改,而且一些操作交给Spring框架就可以帮你完成.
- 在写这个项目中遇到的一些问题:前段信息乱码,分页查询,大部分的js操作,有的时候可能并不是代码的问题...等等,但是好在坚持下来并逐一解决,这个项目在一些方面还是可以改进,比如多表查询,页面跳转动画,分页的信息,一些好看的css样式等.
- 知识没有白学的,学无止境.
1.开发环境:
- JDK1.8; mysql8.0.31; mybatis3.5.2; mybatis-spring2.0.2; spring-webmvc及springjdbc都是5.1.9.RELEASE(个人认为目前是用的最舒服的一版)
2.开发软件:
- 可视化前段:VSCode; 数据库:navicat; 后端: IDEA2021.3.3; 服务器: Tomcat
3.其他类插件:lombok PageHelper fileupload
4.该项目通过SSM框架实现,功能包括"基本的CRUD; 用户的登录注册注销; 拦截器; 分页; 文件上传及文件下载,及一些前段操作等"
1. book表
CREATE DATABASE javawork;
USE javawork;
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`bookid` int(0) NOT NULL AUTO_INCREMENT COMMENT 'uuid',
`bookname` varchar(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '图书名称',
`author` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '作者',
`publish` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '出版社',
`introduction` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '简介',
`price` double NOT NULL COMMENT '价格',
`booktype` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '书籍类型',
PRIMARY KEY (`bookid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '图书信息' ROW_FORMAT = Dynamic;
INSERT INTO `book` VALUES (1, '西游记', '吴承恩', '人民文学出版社', '师徒四人去西天取真经', 42, '奇幻类');
INSERT INTO `book` VALUES (2, '三国演义', '罗贯中', '清华大学出版社', '东汉末年分三国。。。', 48, '历史类');
INSERT INTO `book` VALUES (3, '红楼梦', '曹雪芹', '机械工业出版社', '宝玉与众多男女之间故事', 39, '历史类');
INSERT INTO `book` VALUES (4, '资本论', '马克思', '原子能出版社', '马克思的剩余价值理论', 42, '经济类');
INSERT INTO `book` VALUES (5, '经济学原理', '马歇尔', '机械工业出版社', '西方经济学界公认为划时代的著作', 66, '经济类');
INSERT INTO `book` VALUES (6, '大变局下的中国法治', '李卫东', '北京大学出版社', '十大经典法学著作', 42, '政治类');
INSERT INTO `book` VALUES (7, '从你的全世界路过', '张嘉佳', '湖南文艺出版社', '38个爱情故事的小说集', 36, '爱情类');
INSERT INTO `book` VALUES (8, '天才在左,疯子在右', '高铭', '武汉大学出版社', '国内第一本精神病人访谈手记', 30, '教育类');
INSERT INTO `book` VALUES (9, '追风筝的人', '卡勒德·胡赛尼', '上海人民出版社', '人性的背叛与救赎', 36, '情感类');
INSERT INTO `book` VALUES (10, '水浒传', '施耐庵', '人民文学出版社', '108位梁山好汉', 52, '武侠类');
INSERT INTO `book` VALUES (11, '羊脂球', '莫泊桑', '北京联合出版公司', '法国社会各阶层的丑恶嘴脸', 41, '社会类');
INSERT INTO `book` VALUES (12, '百年孤独', '加西亚·马尔克斯', '上海译文出版社', '布恩迪亚家族七代人的百年兴衰', 55, '文学类');
INSERT INTO `book` VALUES (13, '平凡的世界', '路遥', '北京十月文艺出版社', '中国西北农村的历史变革', 58, '文学类');
INSERT INTO `book` VALUES (14, '三体', '刘慈欣', '科幻世界出版社', '征服世界的中国科幻神作', 62, '科幻类');
INSERT INTO `book` VALUES (15, '解忧杂货店', '东野圭谷', '南海出版公司', '收集烦恼和困扰的杂货店', 54, '文学类');
INSERT INTO `book` VALUES (16, '白鹿原', '陈忠实', '人民文学出版社', '中国农村的50年变革', 40, '文学类');
INSERT INTO `book` VALUES (17, '茶馆', '舒庆春(老舍)', '社会科学文献出版社', '一个茶馆的近50年经历', 35, '文学类');
INSERT INTO `book` VALUES (18, '围城', '钱锺书', '上海晨光出版社', '外边的人想进去,里面的人想出来', 30, '文学类');
INSERT INTO `book` VALUES (19, '海边的卡夫卡', '村上春树', '上海译文出版社', '田村卡夫卡的精神救赎', 40, '文学类');
INSERT INTO `book` VALUES (20, '我这一辈子', '舒庆春(老舍)', '中国华侨出版社', '舒庆春的一生', 36, '其他类');
INSERT INTO `book` VALUES (21, '世上另一个我', '萨拉·帕坎南', '湖南文艺出版社', '我在别人设定的角色里拼命挣扎,以为那是我想要的人生', 28, '亲情类');
INSERT INTO `book` VALUES (22, '看见', '柴静', '广西师范大学出版社', '中国社会十年变迁的备忘录', 40, '社会文学类');
2. user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户密码\r\n',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `user` VALUES (1, 'admin', '123456');
新建Maven项目"Book"
1. 右键单击Book模块,选择框架支持,选择web应用程序(4.0版本);也可以在选择Maven项目是使用web-app模板,但是不推荐.
然后在项目中会多出来一个web的文件夹,注意:文件夹图标的小圆点一定要是亮着的,否则去Facet中调整选择到当前的项目.
2. 引入依赖
4.0.0
com.gcx
Book
1.0-SNAPSHOT
8
8
junit
junit
4.12
mysql
mysql-connector-java
8.0.31
com.mchange
c3p0
0.9.5.2
javax.servlet
servlet-api
2.5
javax.servlet.jsp
jsp-api
2.2
javax.servlet
jstl
1.2
org.mybatis
mybatis
3.5.2
org.mybatis
mybatis-spring
2.0.2
org.springframework
spring-webmvc
5.1.9.RELEASE
org.springframework
spring-jdbc
5.1.9.RELEASE
org.projectlombok
lombok
1.18.24
org.aspectj
aspectjweaver
1.9.7
commons-fileupload
commons-fileupload
1.4
javax.servlet
javax.servlet-api
4.0.1
com.github.pagehelper
pagehelper
5.3.2
src/main/java
**/*.properties
**/*.xml
false
src/main/resources
**/*.properties
**/*.xml
false
3.为了避免出现404,创建lib文件(必须确保所有依赖已加入到maven中)
单击加号后选择库文件,全选,添加,应用即可
4. 配置Tomcat服务器
然后应用,确认即可
5. 测试Tomcat服务器能否正常运行
启动Tomcat后浏览器进入名为$Title$的index.jsp页面,并显示$END信息,表示Tomcat配置没问题
1. 创建项目结构
java文件夹下属于源码文件,resources文件夹下属于资源文件,web下是前端的一些配置文件及页面.
2. 开始编写实体类
实体类名需要与数据库表名一致
Book
package com.gcx.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuppressWarnings("all")
public class Book {
private int bookid;
private String bookname;
private String author;
private String publish;
private String introduction;
private Double price;
private String booktype;
}
User
package com.gcx.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String username;
private String password;
}
3. 编写持久层(dao层)
BookMapper接口
package com.gcx.dao;
import com.gcx.pojo.Book;
import com.gcx.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BookMapper {
// 增加一本书
int addBook(Book book);
// 删除一本书
int deleteBookById(@Param("bookid") int id);
// 更新一本书
int updateBook(Book book);
// 查询一本书
Book queryBookById(@Param("bookid") int id);
// 通过书名查询书籍,因为可能是一个集合,所以用List
List queryBookByName(@Param("bookname") String bookname);
// 获取登录信息
User findUserByNameAndPassword(User user);
// 分页
List findList();
// 注册
int adduser(User user);
}
因为要通过mybatis链接数据库,所以要配置它的核心配置文件: mybatis-config.xml
database.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/javawork?useSSL=true&useUnicode=true&characterEncoding=utf8&ServerTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=123456
spring-dao.xml
helperDialect = mysql
reasonable = true
applicationContext.xml
有报错先不用管,是因为还没有配置对应的XML文件.
注意,这里上边会提示要配置应用程序的上下文
点击配置应用程序上下文,创建新的程序上下文
点击确定就可以了,进入项目设置,点击模块,查看是否配置成功
到此数据库链接完成,配置BookMapper.xml
insert into book(bookname,author,publish,introduction,price,booktype)
values(#{bookname},#{author},#{publish},#{introduction},#{price},#{booktype});
delete from book where bookid =#{bookid};
update book set bookname=#{bookname},author=#{author},publish=#{publish},introduction=#{introduction},price=#{price},booktype=#{booktype}
where bookid=#{bookid};
insert into user(username,password)
values (#{username},#{password});
4. 编写业务层代码(service接口及实现类)
BookService
package com.gcx.service;
import com.gcx.pojo.Book;
import com.gcx.pojo.User;
import com.github.pagehelper.PageInfo;
public interface BookService {
// 增加一本书
int addBook(Book book);
// 删除一本书
int deleteBookById(int id);
// 更新一本书
int updateBook(Book book);
// 查询一本书
Book queryBookById(int id);
// 通过书名查询书籍
PageInfo queryBookByName(String bookname);
// 获取登录信息
User findUserByNameAndPassword(User user);
// 分页查询
PageInfo findList(Integer pageNum, Integer pageSize);
// 注册
int adduser(User user);
}
BookServiceImpl
package com.gcx.service;
import com.gcx.dao.BookMapper;
import com.gcx.pojo.Book;
import com.gcx.pojo.User;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
public class BookServiceImpl implements BookService {
private BookMapper bookMapper;
public void setBookMapper(BookMapper bookMapper) {
this.bookMapper = bookMapper;
}
@Override
public int addBook(Book book) {
return bookMapper.addBook(book);
}
@Override
public int deleteBookById(int id) {
return bookMapper.deleteBookById(id);
}
@Override
public int updateBook(Book book) {
return bookMapper.updateBook(book);
}
@Override
public Book queryBookById(int id) {
return bookMapper.queryBookById(id);
}
@Override
public PageInfo queryBookByName(String bookname) {
List list = bookMapper.queryBookByName(bookname);
return new PageInfo<>(list);
}
@Override
public User findUserByNameAndPassword(User user) {
return bookMapper.findUserByNameAndPassword(user);
}
@Override
public PageInfo findList(@RequestParam Integer pageNum,
@RequestParam Integer pageSize) {
// 每页显示多少数据
if (pageSize== null){
pageSize=5;
}
PageHelper.startPage(pageNum,pageSize);
List list = bookMapper.findList();
// for (Books books : list) {
// System.out.println("书籍信息:"+books);
// }
PageInfo PageInfo = new PageInfo(list);
System.out.println("总页数:"+PageInfo.getPages());
System.out.println("总记录数:"+PageInfo.getTotal());
System.out.println("当前页数:"+PageInfo.getPageNum());
System.out.println("当前页面记录数:"+PageInfo.getPageSize());
return new PageInfo<>(list);
}
@Override
public int adduser(User user) {
return bookMapper.adduser(user);
}
}
配置spring-service.xml
配置上下文为applicationContext.xml.
5. 配置spring-mvc.xml
如果在配置拦截器的地方报错,是因为还没有些拦截器的类,可以先创建一个不写内容.
配置上下文为applicationContext.xml
此时在Spring的模块中显示如下:
到这里,底层代码基本完成了.然后就是前后端的链接:
在mvc中是通过Servlet层的HttpServlet来实现的,在SpringMVC中,则是通过Controller层的添加注解或继承Controller接口来实现的.
6. BookController
package com.gcx.controller;
import com.gcx.pojo.Book;
import com.gcx.pojo.User;
import com.gcx.service.BookService;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.net.URLEncoder;
/**
* author: labixiaoxin@
* advice: Controller层可以写的更分工明确;
* 新建LoginController来写登录.注册.注销的实现;
* 新建PageController用来写分页的实现;
* ...其他类似
*/
@Controller
@RequestMapping("/book")
@SuppressWarnings("all")
public class BookController {
@Autowired
@Qualifier("BookServiceImpl")
private BookService bookService;
// 跳转到登录页
@RequestMapping("toLogin")
public String Login() {
return "Login";
}
// 进入登录页
/**
*
* @param session 将数据保存在session中
* @param user 数据库内的用户登录信息
* @param model 将数据通过el表达式显示在页面
* @return 跳转页面
*/
@RequestMapping("Login")
public String Login(HttpSession session, User user, Model model) {
// 用来获取user内的信息
User userByNP = bookService.findUserByNameAndPassword(user);
/**
*
* 调用业务层接口内方法
* 判断用户信息是否正确,且用户信息不为空.
* 将user信息保存在session中,并进入首页
* 否则返回error1信息
*/
if (userByNP != null) {
session.setAttribute("userLoginInfo", user);
System.out.println(user);
return "redirect:/book/allbook/1";
} else {
model.addAttribute("error1", "账号或密码错误,请重新输入");
return "Login";
}
}
// 跳转注册
@RequestMapping("toregisterPage")
public String toregisterPage() {
return "register";
}
// 注册sql
/**
*
* @param username
* @param password 用@RequestParam获取前段传递的信息获取用户名和密码
* @param session
* @return
*/
@GetMapping("register")
public String register(
@RequestParam("username") String username,
@RequestParam("password") String password, HttpSession session) {
User user = new User();
user.setUsername(username);
user.setPassword(password);
bookService.adduser(user);
session.setAttribute("userLoginInfo", user);
System.out.println(user);
return "Login";
}
/**
*
* 两种方法:
* 1.removeAttribute 移除指定的信息
* 2.invalidate 移除session中所有信息
* @param
* @return
*/
@RequestMapping("destory")
public String destory(HttpSession session) {
session.removeAttribute("userLoginInfo");
// session.invalidate();
// User user = new User();
// 验证是否注销成功
// System.out.println(user.toString());
return "Login";
}
// 登录页面进入首页
@RequestMapping("toallbook")
public String toallbook() {
return "allbook";
}
// 查询全部书籍(首页)
/**
*
*对展示页面进行分页
* @param pageIndex 当前页码
* @param model 给前端传信息
* if:如果当前页码<=1,则设置为第一页
* pageSize=null=5
* 在Service接口中返回PageInfo类型,保存到"PageInfo"中,方便前段调用PageInfo属性
* @return
*/
@GetMapping("allbook/{num}")
public String list(@PathVariable("num") Integer pageIndex, Model model) {
if (pageIndex <= 1) {
pageIndex = 1;
}
PageInfo list = bookService.findList(pageIndex, null);
model.addAttribute("PageInfo", list);
return "allbook";
}
//跳转到新增书籍页面
@RequestMapping("toAddBook")
public String toAddPaper() {
return "addBook";
}
//执行sql新增书籍
@RequestMapping("addBook")
public String addBook(Book book) {
bookService.addBook(book);
return "redirect:/book/allbook/1";
}
// 跳转到更改书籍页面
@RequestMapping("toupdateBook")
public String toupdatePaper(int id, Model model) {
Book book = bookService.queryBookById(id);
model.addAttribute("Book", book);
return "updatebook";
}
// 执行sql更改书籍
@RequestMapping("updateBook")
public String updateBook(Book book) {
bookService.updateBook(book);
return "redirect:/book/allbook/1";
}
// 执行sql删除书籍
/**
*
* @param id restful风格
* @return
*/
@RequestMapping("deletebook/{bookid}")
public String deleteBook(@PathVariable("bookid") int id) {
bookService.deleteBookById(id);
return "redirect:/book/allbook/1";
}
// 执行SQL(根据书籍名称)查询书籍
/**
*
* @param queryBookname 查询书籍的名字
* @param model
* @return
*/
@GetMapping("querybook")
public String queryBook(@RequestParam("queryBookname") String queryBookname,
Model model) {
PageInfo list = bookService.queryBookByName(queryBookname);
// 如果输入为空或输入的信息不存在,返回error信息
// if (queryBookname == null) {
// list = bookService.queryAllBook();
// model.addAttribute("error1", "没有该书籍,请重新查询");
// }
System.out.println(list);
model.addAttribute("PageInfo", list);
return "allbook";
}
/**
* 文件上传
* @param file
* @param request
* @return
* @throws IOException
*
* @RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
* 批量上传CommonsMultipartFile则为数组即可
*/
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
// file.getOriginalFilename() :获取文件名;
String uploadFileName = file.getOriginalFilename();
// 如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/book/allbook/1";
}
System.out.println("上传文件名 : "+uploadFileName);
// 上传路径保存设置(绝对路径)
String path = "C:\\Users\\Gu_cx\\Desktop\\Book\\web\\upload";
// 如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
// 读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/book/allbook/1";
}
// 下载图片
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
// 要下载的图片地址(绝对路径)
String path = "C:\\Users\\Gu_cx\\Desktop\\Book\\web\\img\\idea.png";
String fileName = path.substring(path.lastIndexOf("\\")+1);
// 1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
// 设置响应头(百度web下载文件的头信息)
response.setHeader("Content-Disposition",
"attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
// 2、 读取文件--输入流
InputStream input=new FileInputStream(path);
// 3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
// 4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
}
7. LoginInterceptor拦截器
package com.gcx.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/**
*
*因为是boolean 的返回类型,true代表可以通过拦截器,false代表被拦截器拦截,不能够通过
*/
// 设置编码格式
request.setCharacterEncoding("UTF-8");
HttpSession session = request.getSession();
// 通过Controller中的setAttribute保存的信息,在这里通过get获取到,如果userLoginInfo内不为空时可以通过
if ( session.getAttribute("userLoginInfo")!=null){
System.out.println("执行了登录拦截器=>111");
return true;
}
// getRequestURI().contains属于获取URL的地址,让URL进入到toLogin;Login;toregisterPage;register时可以通过
if (request.getRequestURI().contains("toLogin")){
System.out.println("执行了登录拦截器=>222");
return true;
}
if (request.getRequestURI().contains("Login")){
System.out.println("执行了登录拦截器=>333");
return true;
}
if (request.getRequestURI().contains("toregisterPage")){
System.out.println("执行了登录拦截器=>444");
return true;
}
if (request.getRequestURI().contains("register")){
System.out.println("执行了登录拦截器=>555");
return true;
}
// 判断当不满足以上条件使,都要被拦截器拦截,不能通过并重定向到Login.jsp页面
request.getRequestDispatcher("/WEB-INF/jsp/Login.jsp").forward(request,response);
return false;
}
}
到这里,源码及配置文件层都已经完成
首先,因为视图解析器中的前缀是WEB-INF下的jsp文件夹,所以在WEB-INF下新建jsp文件
1. 首先index.jsp(跳转进入页)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 蜡笔小鑫
Date: 2022/12/29
Time: 15:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
首页
<%-- 使用纯jquery实现轮播图;
优点:适合新手;
缺点:浪费资源,每次加载页面都要更新请求,占用内存和网络--%>
欢迎进入书籍管理系统
2. 首页 allbook
<%--
Created by IntelliJ IDEA.
User: 蜡笔小鑫
Date: 2022/12/25
Time: 14:38
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
书籍展示
书籍展示
书籍名称
作者
出版社
书籍编号
详情
价格
书籍类别
操作
/*调用PageInfo里的list属性*/
${book.bookname}
${book.author}
${book.publish}
${book.bookid}
${book.introduction}
${book.price}
${book.booktype}
修改
|
删除
<%-- 如果当前页码-1>=0,则显示首页,即在第一页时不显示首页--%>
- 首页
<%-- 当有上一页"且"总页数>2时 显示上一页--%>
- < 上一页
<%-- 循环显示页数--%>
<%-- 只需要一个get请求去获得到pageIndex--%>
- ${num}
<%-- 当有下一页"且"总页数>2"且"当前页不是最后一页时 显示下一页--%>
- 下一页 >
<%-- 当前页码+1<=总页数,则显尾页,即在最后一页时不显示尾页--%>
- 尾页
共${PageInfo.pages}页
<%-- 每页显示--%>
<%-- --%>
<%-- 条数据--%>
每页显示${PageInfo.pageSize}条信息
共${PageInfo.total}条信息
3. 新增书籍页面 addBook.jsp
<%--
Created by IntelliJ IDEA.
User: 蜡笔小鑫
Date: 2022/12/25
Time: 17:24
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
添加书籍
书籍列表----新增书籍
4. 修改书籍页面 updatebook.jsp
<%--
Created by IntelliJ IDEA.
User: 蜡笔小鑫
Date: 2022/12/25
Time: 17:49
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
修改书籍
书籍列表----修改书籍
5. 登录页 Login.jsp
<%--
Created by IntelliJ IDEA.
User: 蜡笔小鑫
Date: 2022/12/30
Time: 14:20
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录
6. 注册页 register.jsp
<%--
Created by IntelliJ IDEA.
User: 蜡笔小鑫
Date: 2022/12/30
Time: 15:49
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
注册
7. css层
index.css
header {
width: 1000px;
height: 600px;
position: relative;
margin: 70px 60px auto;
}
.bigBox{
width:1000px;
height:600px;
overflow:hidden;
overflow-x: auto;
white-space: nowrap;
}
.bigBox img{
width: 100%;
height: 100%;
}
.left{
width: 70px;
height: 70px;
cursor: pointer;
float: left;
left: 0;
top: 50%;
background: url("../indexImg/left.png") ;
}
.right{
width: 70px;
height: 70px;
cursor: pointer;
float: right;
right: 0;
top: 50%;
background: url("../indexImg/right.png") ;
}
#nav {
bottom: 5px;
left: 30%;
margin: 10px 10px 150px 150px;
}
#nav li {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #ccc;
font-size: 24px;
border-radius: 9px;
color: darkslategrey;
font-family: 'Times New Roman', Times, serif;
margin: 0 25px;
float: left;
cursor: pointer;
list-style: none;
}
#nav li:hover {
background: peru;
}
a{
/*display: inline-block;*/
/*padding-left: 10px;*/
/*text-decoration: none;*/
/*color: black;*/
/*font-size: 30px;*/
width: 250px;
height: 70px;
/*margin: 100px auto;*/
/*text-align: center;*/
/*line-height: 40px;*/
/*background: green;*/
/*border-radius: 5px 0px 0px 5px;*/
}
.texts{
width: 250px;
height: 70px;
text-align: center;
line-height: 40px;
}
h1{
font-family: 黑体, serif;
font-size: xx-large;
font-weight: bold;
margin: 30px 50px 120px 40px;
}
.threesolid{
font-size: 30px;
color:#fefefe;
text-shadow:0px 1px 0px #c0c0c0,
0px 2px 0px #b0b0b0,
0px 3px 0px #a0a0a0,
0px 4px 0px #909090,
0px 5px 10px rgba(0, 0, 0, .9);
}
@-webkit-keyframes stripe-slide {
0% {
background-position: 0% 0;
}
100% {
background-position: 100% 0;
}
}
@keyframes stripe-slide {
0% {
background-position: 0% 0;
}
100% {
background-position: 100% 0;
}
}
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-family: sans-serif;
}
.btn {
overflow: visible;
margin: 0;
padding: 0;
border: 0;
background: transparent;
font: inherit;
line-height: normal;
cursor: pointer;
-moz-user-select: text;
display: block;
text-decoration: none;
text-transform: uppercase;
padding: 16px 36px 22px;
background-color: #fff;
color: #666;
border: 2px solid #666;
border-radius: 6px;
margin-bottom: 16px;
transition: all 0.5s ease;
}
.btn::-moz-focus-inner {
padding: 0;
border: 0;
}
.btn--stripe {
overflow: hidden;
position: relative;
}
.btn--stripe:after {
content: "";
display: block;
height: 7px;
width: 100%;
background-image: repeating-linear-gradient(45deg, #666, #666 1px, transparent 2px, transparent 5px);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
border-top: 1px solid #666;
position: absolute;
left: 0;
bottom: 0;
background-size: 7px 7px;
}
.btn--stripe:hover {
background-color: #666;
color: #fff;
border-color: #000;
}
.btn--stripe:hover:after {
background-image: repeating-linear-gradient(45deg, #fff, #fff 1px, transparent 2px, transparent 5px);
border-top: 1px solid #000;
-webkit-animation: stripe-slide 12s infinite linear forwards;
animation: stripe-slide 12s infinite linear forwards;
}
.btn--large {
width: 50%;
}
.btn--radius {
border-radius: 36px;
}
register.css
header {
width: 1000px;
height: 600px;
position: relative;
margin: 70px 60px auto;
}
.bigBox{
width:1000px;
height:600px;
overflow:hidden;
overflow-x: auto;
white-space: nowrap;
}
.bigBox img{
width: 100%;
height: 100%;
}
.left{
width: 70px;
height: 70px;
cursor: pointer;
float: left;
left: 0;
top: 50%;
background: url("../indexImg/left.png") ;
}
.right{
width: 70px;
height: 70px;
cursor: pointer;
float: right;
right: 0;
top: 50%;
background: url("../indexImg/right.png") ;
}
#nav {
bottom: 5px;
left: 30%;
margin: 10px 10px 150px 150px;
}
#nav li {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #ccc;
font-size: 24px;
border-radius: 9px;
color: darkslategrey;
font-family: 'Times New Roman', Times, serif;
margin: 0 25px;
float: left;
cursor: pointer;
list-style: none;
}
#nav li:hover {
background: peru;
}
a{
/*display: inline-block;*/
/*padding-left: 10px;*/
/*text-decoration: none;*/
/*color: black;*/
/*font-size: 30px;*/
width: 250px;
height: 70px;
/*margin: 100px auto;*/
/*text-align: center;*/
/*line-height: 40px;*/
/*background: green;*/
/*border-radius: 5px 0px 0px 5px;*/
}
.texts{
width: 250px;
height: 70px;
text-align: center;
line-height: 40px;
}
h1{
font-family: 黑体, serif;
font-size: xx-large;
font-weight: bold;
margin: 30px 50px 120px 40px;
}
.threesolid{
font-size: 30px;
color:#fefefe;
text-shadow:0px 1px 0px #c0c0c0,
0px 2px 0px #b0b0b0,
0px 3px 0px #a0a0a0,
0px 4px 0px #909090,
0px 5px 10px rgba(0, 0, 0, .9);
}
@-webkit-keyframes stripe-slide {
0% {
background-position: 0% 0;
}
100% {
background-position: 100% 0;
}
}
@keyframes stripe-slide {
0% {
background-position: 0% 0;
}
100% {
background-position: 100% 0;
}
}
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-family: sans-serif;
}
.btn {
overflow: visible;
margin: 0;
padding: 0;
border: 0;
background: transparent;
font: inherit;
line-height: normal;
cursor: pointer;
-moz-user-select: text;
display: block;
text-decoration: none;
text-transform: uppercase;
padding: 16px 36px 22px;
background-color: #fff;
color: #666;
border: 2px solid #666;
border-radius: 6px;
margin-bottom: 16px;
transition: all 0.5s ease;
}
.btn::-moz-focus-inner {
padding: 0;
border: 0;
}
.btn--stripe {
overflow: hidden;
position: relative;
}
.btn--stripe:after {
content: "";
display: block;
height: 7px;
width: 100%;
background-image: repeating-linear-gradient(45deg, #666, #666 1px, transparent 2px, transparent 5px);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
border-top: 1px solid #666;
position: absolute;
left: 0;
bottom: 0;
background-size: 7px 7px;
}
.btn--stripe:hover {
background-color: #666;
color: #fff;
border-color: #000;
}
.btn--stripe:hover:after {
background-image: repeating-linear-gradient(45deg, #fff, #fff 1px, transparent 2px, transparent 5px);
border-top: 1px solid #000;
-webkit-animation: stripe-slide 12s infinite linear forwards;
animation: stripe-slide 12s infinite linear forwards;
}
.btn--large {
width: 50%;
}
.btn--radius {
border-radius: 36px;
}
style.css(登录页样式)
@charset "UTF-8";
* {
margin: 0;
padding: 0;
}
/*公共CSS*/
.box {
width: 100vw;
height: 100vh;
background-color: rgb(29, 67, 89);
}
.box .content .login-wrapper .login-form .astyle{
color: black;
margin-left: 200px;
text-decoration: none;
}
.box .content .login-wrapper .login-form .astyle:hover{
color: #6363ee;
font-weight: bolder;
}
.box .content .login-wrapper h1 {
text-align: center;
}
.box .content .login-wrapper .login-form .form-item {
margin: 20px 0;
}
.box .content .login-wrapper .login-form .form-item span {
display: block;
margin: 5px 20px;
font-weight: 100;
}
.box .content .login-wrapper .login-form .form-item .input-item {
width: 100%;
border-radius: 40px;
padding: 20px;
box-sizing: border-box;
font-size: 20px;
font-weight: 200;
}
.box .content .login-wrapper .login-form .form-item .input-item:focus {
outline: none;
}
.box .content .login-wrapper .login-form .login-btn {
width: 100%;
border-radius: 40px;
color: #fff;
border: 0;
font-weight: 100;
margin-top: 10px;
cursor: pointer;
}
.box .content .login-wrapper .divider {
width: 100%;
margin: 20px 0;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.box .content .login-wrapper .divider span:nth-child(1) {
flex: 1;
}
.box .content .login-wrapper .divider span:nth-child(3) {
flex: 1;
}
.box .content .login-wrapper .divider .line {
display: inline-block;
max-width: 30%;
width: 30%;
}
.box .content .login-wrapper .divider .divider-text {
vertical-align: middle;
margin: 0px 20px;
line-height: 0px;
display: inline-block;
width: 100px;
}
.box .content .login-wrapper .other-login-wrapper {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.box .content .login-wrapper .other-login-item {
border: 1px solid rgb(214, 222, 228);
padding: 10px;
margin: 10px;
cursor: pointer;
}
/*一般大于手机的尺寸CSS*/
@media (min-width: 767px) {
.box {
background-color: rgb(29, 67, 89);
}
.box .content {
width: 85vw;
height: 90vh;
background: url('../img/login_two.jpg') no-repeat;
background-size: 90% 100%;
position: absolute;
right: 15%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 20px;
background-color: #fff;
}
.box .content .login-wrapper {
width: 25vw;
position: absolute;
right: 15%;
top: 50%;
transform: translateY(-50%);
}
.box .content .login-wrapper h1 {
text-align: center;
font-size: 45px;
color: rgb(81, 100, 115);
margin-bottom: 40px;
}
.box .content .login-wrapper .login-form {
margin: 10px 0;
}
.box .content .login-wrapper .login-form .form-item span {
color: rgb(81, 100, 115);
}
.box .content .login-wrapper .login-form .form-item .input-item {
height: 60px;
border: 1px solid rgb(214, 222, 228);
}
.box .content .login-wrapper .login-form .login-btn {
height: 50px;
background-color: rgb(59, 72, 89);
font-size: 20px;
}
.box .content .login-wrapper .divider .line {
border-bottom: 1px solid rgb(214, 222, 228);
}
.box .content .login-wrapper .other-login-item {
border-radius: 20px;
}
.box .content .login-wrapper .other-login-item img {
width: 40px;
height: 40px;
}
}
/*手机端CSS*/
@media (max-width: 768px) {
.box .content {
width: 100vw;
height: 100vh;
background: url("../img/login_bg_phone.png") no-repeat;
background-size: 100% 100%;
display: flex;
align-items: flex-start;
justify-content: center;
}
.box .content .login-wrapper {
width: 70%;
height: 60%;
padding-top: 15%;
}
.box .content .login-wrapper h1 {
font-size: 30px;
color: #fff;
}
.box .content .login-wrapper .login-form .form-item {
margin: 10px 0;
}
.box .content .login-wrapper .login-form .form-item span {
color: rgb(113, 129, 141);
}
.box .content .login-wrapper .login-form .form-item .input-item {
height: 30px;
border: 1px solid rgb(113, 129, 141);
background-color: transparent;
color: #fff;
}
.box .content .login-wrapper .login-form .login-btn {
height: 40px;
background-color: rgb(235, 95, 93);
font-size: 16px;
}
.box .content .login-wrapper .divider .line {
border-bottom: 1px solid #fff;
}
.box .content .login-wrapper .divider .divider-text {
color: #fff;
}
.box .content .login-wrapper .other-login-item {
border-radius: 15px;
}
.box .content .login-wrapper .other-login-item img {
width: 35px;
height: 35px;
}
}/*# sourceMappingURL=style.css.map */
8. js
index.js
// 五张图片的url
var oImg1 = "indexImg/1.jpg";
var oImg2 = "indexImg/2.jpg";
var oImg3 = "indexImg/3.jpg";
var oImg4 = "indexImg/4.jpg";
var oImg5 = "indexImg/5.jpg";
var oImg6 = "indexImg/6.jpg";
// 把5张图片存入一个数组
var arr = [oImg1, oImg2, oImg3, oImg4, oImg5 ,oImg6];
window.onload = function() {
//刚加载时第一张图片1号背景颜色
document.getElementById("1").style.background = "peru";
run()
}
//轮播
function run() {
timer = setInterval(function() {
//随机点数字时能接着变化
var pic = document.getElementById("insert").name;
//如果为最后一张图片则重新循环
if (pic == 5) {
pic = -1;
}
//点一个数字该数字背景颜色变化其余的不变
var aLi = document.getElementsByTagName("li");
for (var j = 0; j < aLi.length; j++) {
aLi[j].style.backgroundColor = "#CCCCCC";
}
var i = parseInt(pic);
// 图片地址
document.getElementById("insert").src = arr[i + 1];
document.getElementById("insert").name = i + 1;
//数字随图片变化
switch (i) {
case 0:
var temp = '2';
break;
case 1:
var temp = '3';
break;
case 2:
var temp = '4';
break;
case 3:
var temp = '5';
break;
case 4:
var temp = '6';
break;
case -1:
var temp = '1';
break;
}
document.getElementById(temp).style.background = "peru"
}, 5000)
}
//右箭头
function goForward() {
var temp = document.getElementById("insert").name;
var oBox = document.getElementById("insert");
var aLi = document.getElementsByTagName("li");
// 数字跟着图片一起变
for (var i = 0; i < aLi.length; i++) {
aLi[i].style.backgroundColor = "#CCCCCC";
}
switch (temp) {
case "0":
var n = '2';
break;
case "1":
var n = '3';
break;
case "2":
var n = '4';
break;
case "3":
var n = '5';
break;
case "4":
var n = '6';
break;
case "5":
var n = '1';
break;
}
document.getElementById(n).style.background = "peru"
// 向右移动图片
for (var j = 0; j < arr.length; j++) {
if (j < 5) {
if (temp == j) {
oBox.src = arr[j + 1];
}
} else {
if (temp == 5) {
oBox.src = arr[0];
}
}
}
// 轮到最后一张图片时返回第一张
if (temp < 5) {
oBox.name = parseInt(temp) + 1;
} else {
oBox.name = 0;
}
}
//左箭头
function goBack() {
var temp = document.getElementById("insert").name;
var oBox = document.getElementById("insert")
var aLi = document.getElementsByTagName("li");
// 图片移动时数字也跟着变
for (var i = 0; i < aLi.length; i++) {
aLi[i].style.backgroundColor = "#CCCCCC";
}
switch (temp) {
case "0":
var n = '6';
break;
case "1":
var n = '1';
break;
case "2":
var n = '2';
break;
case "3":
var n = '3';
break;
case "4":
var n = '4';
break;
case "5":
var n = '5';
break;
}
document.getElementById(n).style.background = "peru"
// 向左移动图片
for (var j = 0; j < arr.length; j++) {
if (j > 0) {
if (temp == j) {
oBox.src = arr[j - 1];
}
} else {
if (temp == 0) {
oBox.src = arr[5];
}
}
}
// 轮到第一张图片时返回最后一张
if (temp > 0) {
oBox.name = parseInt(temp) - 1;
} else {
oBox.name = 5;
}
}
//指定图片
function move(num) {
var oBox = document.getElementById("insert");
var temp = document.getElementById("insert").name;
var aLi = document.getElementsByTagName("li");
for (var i = 0; i < aLi.length; i++) {
aLi[i].style.backgroundColor = "#CCCCCC";
}
document.getElementById(num.innerHTML).style.background = "peru"
switch (num.innerHTML) {
case "1":
oBox.src = arr[0];
oBox.name = 0;
break;
case "2":
oBox.src = arr[1];
oBox.name = 1;
break;
case "3":
oBox.src = arr[2];
oBox.name = 2;
break;
case "4":
oBox.src = arr[3];
oBox.name = 3;
break;
case "5":
oBox.src = arr[4];
oBox.name = 4;
break;
case "6":
oBox.src = arr[5];
oBox.name = 5;
break;
}
}
img和indexImg均为图片,可以自行添加.
uplode是文件上传的位置
1. index.jsp
2. 因为拦截器的原因在这里无论点击登录还是进入书籍页面都会被拦截到登录页面 Login.jsp
3. 想要进行注册,进入注册页面 register.jsp
点击注册或立即登录都会重新跳转到登录页面Login,jsp
4. 进行登录,使用的是user表里的用户信息
5. 点击登录进入allbook首页(第一页)
其中包括了Controller层内的大部分操作:新增,修改,删除,查询书籍,回到登录页,注销用户,分页显示,文件的上传及下载
6. 新增书籍页面 addbook.jsp
7. 修改书籍页面 updatebook.jsp
8. 书籍查询
9. 分页操作
10.文件上传
11. 下载
ok ,项目展示到此结束
链接:https://pan.baidu.com/s/1IrCCDYkcxbszNR7dmceEew?pwd=gbz8
提取码:gbz8