9. 获取Cookie/Session
简洁的获取方式(注解获取)
@CookieValue
2.3 返回数据
1. 返回静态页面
//@RestController
@Controller
public class ReturnController {
@RequestMapping("/index")
public String returnIndex() {
return "/index.html"; //返回页面里面的数据
}
}
编写的HTML文件
@Controller: 返回视图 随着前后端分离,后端不处理页面,就返回页面上所需要的数据
@ResponseBody: 返回数据
两个加起来就是@RestController
2. 返回数据
@ResponseBody //因为上方的注解@Controller是返回视图,就会去找HTML,所以要加@ResponseBody返回数据
@RequestMapping("/returnDate")
public String returnDate() {
return "返回视图需要的数据";
}
@Responsebody
可以修饰类,也可以修饰方法
修饰类的时候,表示这个类下的所有方法,返回的均为数据
修饰方法的时候,表示该方法返回的都是数据
如果一个类中的所有方法返回的都是数据,我们就把这个注解加在类上
3. 返回html代码片段
@ResponseBody //因为上方的注解@Controller是返回视图,就会去找HTML,所以要加@ResponseBody返回数据
@RequestMapping("/returnHtml")
public String returnHtml() {
return "<h1>返回HTML代码片段<h1>";
}
4. 返回JSON
@ResponseBody //因为上方的注解@Controller是返回视图,就会去找HTML,所以要加@ResponseBody返回数据
@RequestMapping("/returnJson")
public Person returnJson() {
Person person = new Person(); //创建对象
person.setId(12);
person.setName("caijun");
person.setAge(23);
return person;
}
当我们的接口返回的是String时,content-Type是text/html
当我们的接口返回的是对象/Map时,content-Type自动设置为application/json
5. 设置状态码
状态码不影响页面的显示
@ResponseBody //因为上方的注解@Controller是返回视图,就会去找HTML,所以要加@ResponseBody返回数据
@RequestMapping("/setStatus")
public String setStatus(HttpServletResponse response) {
response.setStatus(401); //通常表示没有登录
return "设置状态码";
}
综合练习-加法计算器
需求分析: 加法计算器功能,对两个整数进⾏相加,需要客⼾端提供参与计算的两个数,服务端返回这两个整数计算的结果
接口定义:
- 请求路径: calc/sum
- 请求方式: GET/POST
- 接口描述: 计算两个整数相加
请求参数:
参数名 | 类型 | 是否必须 | 备注 |
num1 | Integer | 是 | 参与计算的第一个数 |
num2 | Integer | 是 | 参与计算的第二个数 |
响应数据:
Content-Type: test/html
响应内容: 计算机计算结果: 8
编写前端html文件放入static文件夹
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="calc/sum" method="post">
<h1>计算器</h1>
数字1:<input name="num1" type="text"><br>
数字2:<input name="num2" type="text"><br>
<input type="submit" value=" 点击相加 ">
</form>
</body>
</html>
运行代码后直接访问
编写后端代码
//加法计算器
@RequestMapping("/calc")
@RestController
public class CalcController {
@RequestMapping("/sum")
public String sum(Integer num1, Integer num2) {
Integer sum = num1 + num2;
return "计算结果为: "+ sum;
}
注意:后端代码的命名要与前端命名一致
综合练习-用户登录
需求:用户输⼊账号和密码,后端进⾏校验密码是否正确
1. 如果不正确,前端进⾏用户告知
2. 如果正确,跳转到首页.首页显⽰当前登录⽤⼾
3. 后续再访首页,可以获取到登录用户信息
登录案例
1. 登录接口
接口: /user/login
参数: userName = ? & password = ?
接口返回: 校验成功还是失败(true/false)
2. 获取用户登录信息
接口: /user/getUserInfo
接口返回: 当前登录用户的名称
后端服务代码
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/login")
public Boolean login(String userName, String password, HttpSession session) {
//校验参数的合法性
if(userName == null || password == null || userName.length() == 0 ||password.length() == 0) {
return false;
}
//另一种 (有没有长度)
// if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {
// return false;
// }
//进行用户名和密码的校验
if ("admin".equals(userName) && "admin".equals(password)) {
//设置session
session.setAttribute("userName", "admin");
return true;
}
return false;
}
/* @RequestMapping("/getUserInfo")
public String getUserInfo(HttpSession session) { //session如果没有的话会自己创建一个空的
//从Session 获取登录用户
String userName = (String) session.getAttribute("userName");
return userName;
}*/
@RequestMapping("/getUserInfo")
public String getUserInfo(HttpServletRequest request) { //session如果没有的话会自己创建一个空的
//从Session 获取登录用户
HttpSession session = request.getSession();
String userName = null;
if (session != null) {
userName = (String) session.getAttribute("userName");
}
return userName;
}
}
前端页面代码
登录页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h1>用户登录</h1>
用户名:<input name="userName" type="text" id="userName"><br>
密码:<input name="password" type="password" id="password"><br>
<input type="button" value="登录" onclick="login()">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
function login() {
console.log("登录...");
$.ajax({
url: "/user/login",
type: "post",
data:{
"userName": $("#userName").val(),
"password": $("#password").val()
},
success:function(result){
if(result){
location.href = "/index.html";
// location.assign();
}else{
alert("密码错误");
}
}
});
}
</script>
</body>
</html>
用户页
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户登录首页</title>
</head>
<body>
登录人: <span id="loginUser"></span>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
//页面加载时, 就去调用后端请求
$.ajax({
url: "/user/getUserInfo",
type:"get",
success:function(username){
$("#loginUser").text(username);
}
});
</script>
</body>
</html>
运行测试
综合练习-留言板
需求:
界面如下图所示
- 输入留言信息,点击提交,后端把数据存储起来
- 页面展示输入的表白信息
前端服务代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>留言板</title>
<style>
.container {
width: 350px;
height: 300px;
margin: 0 auto;
/* border: 1px black solid; */
text-align: center;
}
.grey {
color: grey;
}
.container .row {
width: 350px;
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
}
.container .row input {
width: 260px;
height: 30px;
}
#submit {
width: 350px;
height: 40px;
background-color: orange;
color: white;
border: none;
margin: 10px;
border-radius: 5px;
font-size: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>留言板</h1>
<p class="grey">输入后点击提交, 会将信息显示下方空白处</p>
<div class="row">
<span>谁:</span> <input type="text" name="" id="from">
</div>
<div class="row">
<span>对谁:</span> <input type="text" name="" id="to">
</div>
<div class="row">
<span>说什么:</span> <input type="text" name="" id="say">
</div>
<input type="button" value="提交" id="submit" onclick="submit()">
<!-- <div>A 对 B 说: hello</div> -->
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
//页面加载时,请求后端,获取留言列表
$.ajax({
url:"/message/getMessageInfo",
type:"get",
success:function (messages){
for (var m of messages) {
//拼接节点的HTML
var divE = "<div>" + m.from + "对" + m.to + "说:" + m.say + "</div>";
//把节点添加到页面上
$(".container").append(divE);
}
}
})
function submit() {
//1. 获取留言的内容(获取输入框的值)
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from == '' || to == '' || say == '') {
return;
}
//提交留言
$.ajax({
url: "/message/publish",
type: "post",
data: { //把这里面的数据传到/message/publish里
"from": from,
"to": to,
"message": say
},
success: function (result) {
if (result) {
//添加成功
//2. 构造节点
var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
} else {
//添加失败
alert("留言板发布失败")
}
}
})
}
</script>
</body>
</html>
写后端代码之前要进行接口定义
- 提交留言: /message/publish 参数对象: MessageInfo(from, to, message) 返回结果: true/false
- 查看所有留言: /message/getMessageList 参数: 无 返回结果: List<MessageInfo>
编写后端服务代码
package org.example.demo.controller;
import org.apache.logging.log4j.message.Message;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RequestMapping("/message")
@RestController
public class MessageController {
private List<MessageInfo> messageInfos = new ArrayList<>();
//提交留言
@RequestMapping("/publish")
public Boolean publishMessage(MessageInfo messageInfo) {
//进行参数的校验
if (!StringUtils.hasLength(messageInfo.getMessage()) ||
!StringUtils.hasLength(messageInfo.getTo()) ||
!StringUtils.hasLength(messageInfo.getFrom()) ) {
return false;
}
//添加留言
messageInfos.add(messageInfo); //添加进内存
return true;
}
//查看留言
@RequestMapping("/getMessageInfo")
public List<MessageInfo> getMessages() {
return messageInfos; //返回集合里所添加的数
}
}
利用postman测试接口
综合练习-图书管理系统
需求:
- 登录: 用户输入账号,.密码完成登录功能
- 列表展示: 展示图书
定义前后端交互接口
1. 登录
URL: /user/login
参数: userName = ?& password = ?
响应: true/false
2. 图书列表展示
URL: /book/getBookList
参数: 无
响应: List<BookInfo>
编写后端服务代码
建一个图书类
package org.example.demo;
import lombok.Data;
import java.math.BigDecimal;
@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-不可借阅
private String statusCN;
}
登录接口
package org.example.demo;
import jakarta.servlet.http.HttpSession;
import jakarta.websocket.Session;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/login") //登录接口
public boolean login(String userName, String password, HttpSession session) {
//检验参数
if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {
return false;
}
/*
if(userName.("admin")) {} 这种写法,如果userName为null,会报空指针异常
*/
//验证账号密码是否正确
if("admin".equals(userName) && "admin".equals(password)) { //"admin"写在前面
//账号密码正确 存Session
session.setAttribute("userName",userName);
return true;
}
return false;
}
}
图书列表接口
package org.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@RequestMapping("/book")
@RestController
public class BookController {
@RequestMapping("getBookList") //图书列表的接口
public List<BookInfo> getBookList() {
//1. 获取图书的数据
//2. 对图书的数据进行处理
//3. 返回数据
//mock表示虚拟数据
List<BookInfo> bookInfos = mockData();
for (BookInfo bookInfo: bookInfos) {
if(bookInfo.getStatus()==1){
bookInfo.setStatusCN("可借阅");
}else {
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
private List<BookInfo> mockData() {
//对于已知的数据量可以创建List时指定初始容量
List<BookInfo> bookInfos = new ArrayList<>(15); //15设置为固定长度
for (int i = 0; i < 15; i++) {
BookInfo bookInfo = new BookInfo();
bookInfo.setId(i);
bookInfo.setBookName("图书"+i);
bookInfo.setAuthor("作者"+i);
bookInfo.setCount(new Random().nextInt(200)); //库存随机
bookInfo.setPrice(new BigDecimal(new Random().nextInt(100))); //价格随机
bookInfo.setPublish("出版社"+i);
bookInfo.setStatus(i%5==0?1:0);
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
打开postman进行登录接口测试
打开postman进行图书列表接口测试
后端代码测试完成,接下来就可以写前端代码了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/login.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
</head>
<body>
<div class="container-login">
<div class="container-pic">
<img src="pic/computer.png" width="350px">
</div>
<div class="login-dialog">
<h3>登陆</h3>
<div class="row">
<span>用户名</span>
<input type="text" name="userName" id="userName" class="form-control">
</div>
<div class="row">
<span>密码</span>
<input type="password" name="password" id="password" class="form-control">
</div>
<div class="row">
<button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script>
function login() {
$.ajax({
url:"user/login",
type:"post",
data:{ //接口:传送数据给后端
"userName": $("#userName").val(),
"password": $("#password").val(),
},
success:function (result){ //后端返回
if(result) {
location.href = "book_list.html"; //跳转到图书列表页面
}else {
alert("用户名或者密码错误!");
}
}
})
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图书列表展示</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/list.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script src="js/jq-paginator.js"></script>
</head>
<body>
<div class="bookContainer">
<h2>图书列表展示</h2>
<div class="navbar-justify-between">
<div>
<button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>
<button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>
</div>
</div>
<table>
<thead>
<tr>
<td>选择</td>
<td class="width100">图书ID</td>
<td>书名</td>
<td>作者</td>
<td>数量</td>
<td>定价</td>
<td>出版社</td>
<td>状态</td>
<td class="width200">操作</td>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" name="selectBook" value="1" id="selectBook" class="book-select"></td>
<td>4</td>
<td>大秦帝国第四册</td>
<td>我是作者</td>
<td>23</td>
<td>33.00</td>
<td>北京出版社</td>
<td>可借阅</td>
<td>
<div class="op">
<a href="book_update.html?bookId=4">修改</a>
<a href="javascript:void(0)" onclick="deleteBook(4)">删除</a>
</div>
</td>
</tr>
</tbody>
</table>
<div class="demo">
<ul id="pageContainer" class="pagination justify-content-center"></ul>
</div>
<script>
getBookList();
function getBookList() {
$.ajax({
type:"get",
url:"/book/getBookList",
success:function (books) {
var finalHtml = "";
for (var book of books){
//根据每一条记录拼接html,也就是一个tr
finalHtml+='<tr>';
finalHtml+='<td><input type="checkbox" name="selectBook" value="'+book.id+'" id="selectBook" class="book-select"></td>';
finalHtml+='<td>'+book.id+'</td>';
finalHtml+='<td>'+book.bookName+'</td>';
finalHtml+='<td>'+book.author+'</td>';
finalHtml+='<td>'+book.author+'</td>';
finalHtml+='<td>'+book.price+'</td>';
finalHtml+='<td>'+book.publish+'</td>';
finalHtml+='<td>'+book.statusCN+'</td>';
finalHtml+='<td><div class="op">';
finalHtml+='<a href="book_update.html?bookId='+book.id+'">修改</a>';
finalHtml+='<a href="javascript:void(0)" onclick="deleteBook('+book.id+')">删除</a>';
finalHtml+='</div></td></tr>';
}
console.log(finalHtml);
$("tbody").html(finalHtml);
}
})
}
//翻页信息
$("#pageContainer").jqPaginator({
totalCounts: 100, //总记录数
pageSize: 10, //每页的个数
visiblePages: 5, //可视页数
currentPage: 1, //当前页码
first: '<li class="page-item"><a class="page-link">首页</a></li>',
prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
//页面初始化和页码点击时都会执行
onPageChange: function (page, type) {
console.log("第" + page + "页, 类型:" + type);
}
});
function deleteBook(id) {
var isDelete = confirm("确认删除?");
if (isDelete) {
//删除图书
alert("删除成功");
}
}
function batchDelete() {
var isDelete = confirm("确认批量删除?");
if (isDelete) {
//获取复选框的id
var ids = [];
$("input:checkbox[name='selectBook']:checked").each(function () {
ids.push($(this).val());
});
console.log(ids);
alert("批量删除成功");
}
}
</script>
</div>
</body>
</html>
测试: