网站地图页面,写软文的平台有哪些,网页界面设计宽度和安全区,pc端网站模型建设工具PS#xff1a;关于接口定义 接口定义#xff0c;通常由服务器提供方来定义。 1.路径#xff1a;自己定义 2.参数#xff1a;根据需求考虑#xff0c;我们这个接口功能完成需要哪些信息。 3.返回结果#xff1a;考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…PS关于接口定义 接口定义通常由服务器提供方来定义。 1.路径自己定义 2.参数根据需求考虑我们这个接口功能完成需要哪些信息。 3.返回结果考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的技术
前端”是自己在网上找的代码
后端
IDEAMavenMySQLMybatisSSM
实现的功能
用户登录添加图书显示图书列表更新图书删除图书批量删除图书强制登录引入统一功能 做这个管理系统首先我们需要考虑到什么呢 第一步建立数据库 比如登录、用户要输入 用户名 和 密码。 因此对于数据库。我们需要一张用户表。用来存储用户名和密码。 还需要配置数据库 日志文件 搞完数据库相关的。就要写代码了。 第二步创建实体类 我们需要根据数据库字段创建一些实体类。 第三步实现用户登录功能 第四步实现添加图书功能 第五步实现显示图书列表功能 第六步实现更新图书功能 第七步实现删除图书功能 第八步实现批量删除图书 第九步实现强制登录 第十步加上统一功能 预览整体项目 首页 登录进去 可以进行翻页 添加图书 批量删除 修改图书 删除图书 一、建立数据库
1.1配置数据库 日志
server: #端口号配置port: 1208
spring:datasource: # 数据库连接配置url: jdbc:mysql://127.0.0.1:3306/book_test?characterEncodingutf8useSSLfalseusername: rootpassword: 12345678driver-class-name: com.mysql.cj.jdbc.Drivermybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置打印 MyBatis?志map-underscore-to-camel-case: true #配置驼峰?动转换mapper-locations: classpath:mapper/**Mapper.xml # 配置mybatis xml的?件路径在resources/mapper创建所有表的xml?件# classpath对应resources这个目录接下来说明在mapper这个文件夹下面以Mapper.xml结束的都可以被加载# 设置?志?件的?件名
logging:file:name: spring-book.log我们新建一个book_test数据库。 DROP DATABASE IF EXISTS book_test;
CREATE DATABASE book_test DEFAULT CHARACTER SET utf8mb4;①新建一个用户表 DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (id INT NOT NULL AUTO_INCREMENT,user_name VARCHAR ( 128 ) NOT NULL,password VARCHAR ( 128 ) NOT NULL,delete_flag TINYINT ( 4 ) NULL DEFAULT 0,create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( id ), --将 id 列设置为主键保证每条记录唯一UNIQUE INDEX user_name_UNIQUE ( user_name ASC )
--指定了索引的列以及排序方式。在此例中user_name 列按照升序ASC排序。
--默认是升序因此这里 ASC 是可选的。
) ENGINE INNODB --设置存储引擎为 InnoDB支持事务和外键DEFAULT CHARACTER SET utf8mb4 COMMENT ??表;②新建图书表 DROP TABLE IF EXISTS book_info;
CREATE TABLE book_info (id INT ( 11 ) NOT NULL AUTO_INCREMENT,book_name VARCHAR ( 127 ) NOT NULL,author VARCHAR ( 127 ) NOT NULL,count INT ( 11 ) NOT NULL,price DECIMAL (7,2 ) NOT NULL,publish VARCHAR ( 256 ) NOT NULL,status TINYINT ( 4 ) DEFAULT 1 COMMENT 0-?效, 1-正常, 2-不允许借阅,create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( id )
) ENGINE INNODB DEFAULT CHARSET utf8mb4;初始化数据 -- 初始化数据
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( admin, admin );
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( zhangsan, 123456 );
-- 初始化图书数据
INSERT INTO book_info (book_name,author,count, price, publish) VALUES(活着, 余华, 29, 22.00, 北京?艺出版社);
INSERT INTO book_info (book_name,author,count, price, publish) VALUES(平凡的世界, 路遥, 5, 98.56, 北京???艺出版社);
INSERT INTO book_info (book_name,author,count, price, publish) VALUES(三体, 刘慈欣, 9, 102.67, 重庆出版社);
INSERT INTO book_info (book_name,author,count, price, publish) VALUES(?字塔原理, ?肯锡, 16, 178.00, ?主与建设出版社);下面是我们建好后的用户表 图书表 二、创建实体类
2.1 用户实体类UserInfo实体类
package com.qiyangyang.springbook.demos.model;import lombok.Data;
import java.util.Date;
Data
public class UserInfo {private Integer id;private String userName;private String password;private Integer delete_flag;private Date createTime;private Date updateTime;
}2.2 图书实体类 BookInfo实体类
package com.qiyangyang.springbook.demos.model;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
Data
public class BookInfo {private Integer id;private String bookName;private String author;private Integer count;private BigDecimal price;private String publish;private Integer status;//1-可借阅 2-不可借阅 0-已删除private String stateCN;//根据book状态设置描述private Date createTime;private Date updateTime;
}三、实现用户登录接口
3.1约定前后端交互接口
[请求]
/user/login
Content-Type: application/x-www-form-urlencoded; charsetUTF-8[参数]
namezhangsanpassword123456[响应]
true //账号密码验证正确, 否则返回false浏览器给服务器发送 /user/login 这样的 HTTP 请求, 服务器给浏览器返回了一个Boolean类型 的数据.返回true,表示账号密码验证正确 3.2实现后端服务器代码
3.2.1控制层 从数据库查询用户名和密码如果可以查到并且密码一致就认为登录成功。 创建UserController
package com.qiyangyang.springbook.demos.controller;import com.qiyangyang.springbook.demos.model.UserInfo;
import com.qiyangyang.springbook.demos.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;Slf4j
RequestMapping(/user)
RestController
public class UserController {Autowiredprivate UserService userService;RequestMapping(/login)public boolean login(String userName, String password, HttpSession session){/*** 校验参数*/if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){return false;}//判断用户输入的密码和用户输入的密码是否一致//我们需要查询数据库得到数据库的密码UserInfo userInfo userService.queryByName(userName);if(userInfo null){//用户不存在return false;}if(password.equals(userInfo.getPassword())){//将密码置为空不置为空也可以因为Session是在服务器上的数据客户端也看不到//session也是占内存的因此不需要的不存。/*** 如果密码正确* 存Session*///由于密码信息是没用的用不到。我们设置成空。不设置成空也行因为存在服务器。客户端是看不到的userInfo.setPassword();session.setAttribute(user_session,userInfo);return true;}return false;}
}
/**
package com.qiyangyang.springbook.demos.controller;import com.qiyangyang.springbook.demos.model.UserInfo;
import com.qiyangyang.springbook.demos.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;Slf4j
RequestMapping(/user)
RestController
public class UserController {Autowiredprivate UserService userService;RequestMapping(/login)public boolean login(String userName, String password, HttpSession session){/*** 校验参数*/if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){return false;}//判断用户输入的密码和用户输入的密码是否一致//我们需要查询数据库得到数据库的密码UserInfo userInfo userService.queryByName(userName);if(userInfo null){//用户不存在return false;}if(password.equals(userInfo.getPassword())){//将密码置为空不置为空也可以因为Session是在服务器上的数据客户端也看不到//session也是占内存的因此不需要的不存。/*** 如果密码正确* 存Session*///由于密码信息是没用的用不到。我们设置成空。不设置成空也行因为存在服务器。客户端是看不到的userInfo.setPassword();session.setAttribute(user_session,userInfo);return true;}return false;}
}
/*** HttpSession session* 存的是根据SessionId获取的Session对象每一个sessionId对应一个session对象。* 会根据客户端等等判断是新用户还是老用户。服务器里面存了很多session。* SessionId在后端通过服务器生成并通过 Cookie 发送给客户端。**/**/问题1每次我们存的Session都一样。后面用户。存的Session会覆盖前面用户的Session吗 答同一个用户会覆盖不同用户不同客户端不会覆盖。 Session表示的是会话对话。是有来有回的而且是多个回合。 * HttpSession session * 存的是根据SessionId获取的Session对象每一个sessionId对应一个session对象。 * 会根据客户端等等判断是新用户还是老用户。服务器里面存了很多session。 * SessionId在后端通过服务器生成并通过 Cookie 发送给客户端。 问题2如果多个客户端同时访问需不需要加多线程 答不需要因为我们没有使用多线程。 请求的隔离框架已经帮我们做了。因此不考虑多线程。 什么时候才去做多线程呢比如程序里面用到了线程池。才考虑多线程。每个用户进来login函数。信息存放在栈里面栈是线程私有的。堆是线程公有的。这些成员变量存储在栈里面因此每个用户的信息之间没有关系。分别对应不同的对象。 在我们需要进行优化的时候考虑多线程。比如要查询两次数据。第一次得到了密码可以因为业务需要还要查询一次。这时候串行查询觉得太慢了。这时候考虑多线程。就可以进行并行查询。加了多线程我们就要考虑线程安全的情况。代码里用到多线程才考虑多线程。 校验密码我们推荐在业务逻辑层来写由于这里比较简单。我们就写在Controller中 3.2.2 业务层
创建UserService
package com.qiyangyang.springbook.demos.service;import com.qiyangyang.springbook.demos.mapper.UserInfoMapper;
import com.qiyangyang.springbook.demos.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;Service
public class UserService {Autowiredprivate UserInfoMapper userInfoMapper;/*** 从数据库中查询用户信息* param userName* return*/public UserInfo queryByName(String userName){return userInfoMapper.queryByName(userName);}
}3.2.3数据层
创建UserInfoMapper
package com.qiyangyang.springbook.demos.mapper;import com.qiyangyang.springbook.demos.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;Mapper
public interface UserInfoMapper {Select(select * from user_info where delete_flag 0 and user_name#{userName})UserInfo queryByName(String userName);}3.3后端校验 使用Postman校验。多次实验发现校验成功。然后我们再去写前端的代码。 3.4实现前端代码
3.4.1 ajax 部分 script srcjs/jquery.min.js/scriptscriptfunction login() {$.ajax({type:post,url:/user/login,data:{userName:$(#userName).val(),password:$(#password).val()},success:function (result) {if(resulttrue){//验证成功location.href book_list.html;}else {alert(登录失败用户名不存在或密码错误);}}});}/script3.4.2完整前端登录代码
!DOCTYPE html
html langenheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlelink relstylesheet hrefcss/bootstrap.min.csslink relstylesheet hrefcss/login.cssscript typetext/javascript srcjs/jquery.min.js/script
/headbodydiv classcontainer-logindiv classcontainer-picimg srcpic/computer.png width350px/divdiv classlogin-dialogh3登陆/h3div classrowspan用户名/spaninput typetext nameuserName iduserName classform-control/divdiv classrowspan密码/spaninput typepassword namepassword idpassword classform-control/divdiv classrowbutton typebutton classbtn btn-info btn-lg onclicklogin()登录/button/div/div/divscript srcjs/jquery.min.js/scriptscriptfunction login() {$.ajax({type:post,url:/user/login,data:{userName:$(#userName).val(),password:$(#password).val()},success:function (result) {if(resulttrue){//验证成功location.href book_list.html;}else {alert(登录失败用户名不存在或密码错误);}}});}/script
/body/html3.5完整校验前后端交互 输入正确用户名和密码 成功登录并且跳转到图书目录页面。 输入错误用户名和密码。登录失败。弹框显示用户名不存在或密码错误。 四、实现添加图书接口
4.1约定前后端交互 [请求] /book/addBook Content-Type: application/x-www-form-urlencoded; charsetUTF-8 [参数] bookName图书1author作者1count23price36publish出版社1status1 [响应] “成功添加图书” //失败信息, 成功时返回空字符串 我们约定浏览器给服务器发送/book/addBook 这样的HTTP请求。 form表单的形式来提交数据。服务器返回处理结果。返回“”表示图书添加成功。否则返回失败信息。 4.2实现后端服务器代码
4.2.1控制层 创建BookController类 Slf4j
RestController
RequestMapping(book)
public class BookController {Autowiredprivate BookService bookService;RequestMapping(/addBook)public String addBook(BookInfo bookInfo){log.info(添加图书bookInfo:{},bookInfo);/*** 参数校验*/if(!StringUtils.hasLength(bookInfo.getBookName())|| !StringUtils.hasLength(bookInfo.getAuthor())|| !StringUtils.hasLength(bookInfo.getPublish())|| bookInfo.getCount() 0|| bookInfo.getPrice()null){return 参数错误;}/*** 添加图书*//*** 出现错误比如参数错误。添加过程出现异常因为MySQL会出现一些异常* 我们使用try/catch来捕获。*/try {bookService.insertBook(bookInfo);}catch (Exception a){return 内部发生错误请联系管理员;}/*** 返回成功添加吐过表示图书插入成功。*/return 成功添加图书;}
}4.2.2 业务层 创建BookService类 Service
public class BookService {Autowiredprivate BookInfoMapper bookInfoMapper;public Integer insertBook(BookInfo bookInfo){return bookInfoMapper.insertBook(bookInfo);}
}4.2.3 数据层 创建BookInfoMapper Mapper
public interface BookInfoMapper {Insert(insert into book_info(book_name,author,count,price,publish) values (#{bookName},#{author},#{count},#{price},#{publish}))Integer insertBook(BookInfo bookInfo);
}4.3后端测试 填写正确数据返回成功添加图书 填写错误数据返回参数错误 小bug后端服务器问题 count 和 price为字符串时会报400错误。请求参数类型不匹配。 日志显示在绑定 bookInfo 对象时出现了类型转换错误 count 字段后端定义 count 应为 Integer但接收到的值是 五大字符串。price 字段后端定义 price 应为 BigDecimal但接收到的值是 带娃字符串。 因为这些值无法转换成期望的数值类型所以 Spring 在尝试绑定请求参数时抛出了 BindException并返回 HTTP 400 错误表示请求的格式或内容无效。 4…4实现前端代码 4.4.1 form表单 和 ajax 部分 form表单 我们可以把提交的数据写成一个form表单。 form表单 Id 在前端显示页面并没有什么作用。主要是搭配后端来进行前后端交互。 整个表单内容需要提交的话我们可以借助form标签来提交整个表单 data: $(#addBook).serialize(), //序列化//这个函数会把整个表单的所有的input框…等等输入的项目都会提交 提交的结构是以key : value 键值对的形式提交 key就是name value就是输入的值。 form idaddBookdiv classform-grouplabel forbookName图书名称:/labelinputtypetextclassform-controlplaceholder请输入图书名称idbookNamenamebookName//divform idaddBook div classform-grouplabel forbookName图书名称:/labelinput typetext classform-control placeholder请输入图书名称 idbookName namebookName/divdiv classform-grouplabel forbookAuthor图书作者/labelinput typetext classform-control placeholder请输入图书作者 idbookAuthor nameauthor //divdiv classform-grouplabel forbookStock图书库存/labelinput typetext classform-control placeholder请输入图书库存 idbookStock namecount//divdiv classform-grouplabel forbookPrice图书定价/labelinput typenumber classform-control placeholder请输入价格 idbookPrice nameprice/divdiv classform-grouplabel forbookPublisher出版社/labelinput typetext idbookPublisher classform-control placeholder请输入图书出版社 namepublish //divdiv classform-grouplabel forbookStatus图书状态/labelselect classcustom-select idbookStatus namestatusoption value1 selected可借阅/optionoption value2不可借阅/option/select/divdiv classform-group styletext-align: rightbutton typebutton classbtn btn-info btn-lg onclickadd()确定/buttonbutton typebutton classbtn btn-secondary btn-lg onclickjavascript:history.back()返回/button/div/formajax部分 script typetext/javascript srcjs/jquery.min.js/scriptscriptfunction add() {$.ajax({type:post,url:/book/addBook,
//整个表单内容需要提交的话我们可以借助form标签来提交整个表单搭配后端做一些交互来使用的。data: $(#addBook).serialize(),//序列化
//这个函数会把整个表单的所有的input框..等等输入的项目都会提交success:function (result) {if(result 成功添加图书){alert(添加成功);location.href book_list.html;}else {alert(result);}}});}/script4.4.2完整前端添加图书代码
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /title添加图书/titlelink relstylesheet hrefcss/bootstrap.min.css /link relstylesheet hrefcss/add.css //headbodydiv classcontainerdiv classform-inlineh2 styletext-align: left; margin-left: 10pxsvgxmlnshttp://www.w3.org/2000/svgwidth40fill#17a2b8classbi bi-book-halfviewBox0 0 16 16pathdM8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z//svgspan添加图书/span/h2/divform idaddBookdiv classform-grouplabel forbookName图书名称:/labelinputtypetextclassform-controlplaceholder请输入图书名称idbookNamenamebookName//divdiv classform-grouplabel forbookAuthor图书作者/labelinputtypetextclassform-controlplaceholder请输入图书作者idbookAuthornameauthor//divdiv classform-grouplabel forbookStock图书库存/labelinputtypetextclassform-controlplaceholder请输入图书库存idbookStocknamecount//divdiv classform-grouplabel forbookPrice图书定价/labelinputtypenumberclassform-controlplaceholder请输入价格idbookPricenameprice//divdiv classform-grouplabel forbookPublisher出版社/labelinputtypetextidbookPublisherclassform-controlplaceholder请输入图书出版社namepublish//divdiv classform-grouplabel forbookStatus图书状态/labelselect classcustom-select idbookStatus namestatusoption value1 selected可借阅/optionoption value2不可借阅/option/select/divdiv classform-group styletext-align: rightbutton typebutton classbtn btn-info btn-lg onclickadd()确定/buttonbuttontypebuttonclassbtn btn-secondary btn-lgonclickjavascript:history.back()返回/button/div/form/divscript typetext/javascript srcjs/jquery.min.js/scriptscriptfunction add() {$.ajax({type: post,url: /book/addBook,//整个表单内容需要提交的话我们可以借助form标签来提交整个表单搭配后端做一些交互来使用的。data: $(#addBook).serialize(), //序列化//这个函数会把整个表单的所有的input框..等等输入的项目都会提交success: function (result) {if (result 成功添加图书) {alert(添加成功);location.href book_list.html;} else {alert(result);}},});}/script/body
/html4.5完整校验前后端交互 输入正确数据 成功添加到我们的数据库中。 输入错误数据。 弹框提示输入参数错误 本篇内容已经很多。
后续内容在下一篇文章中