目录
分析程序报错的步骤
案例
一.加法计算器
二.实现用户登录
1.登录接口
2.获取用户的登录信息
三.留言板
1.接口定义
2.完成后端代码
3.测试后端代码
四.图书管理系统
1.定义接口
2.后端代码
3.测试后端代码
4.前端交互代码
应用分层
1.三层架构
1.定位是前端还是后端:通过日志
1)前端:F12、看控制台
2)后端:接口、控制台
2.判断请求是否到达后端
1)后端代码在相应方法的第一行,通过打印一些标记的字符串来判断。运行后如果没有打印内容则请求没有到达后端
2)抓包查看访问的接口是否正确
3.当感觉前端代码没有错,后端却接收不到请求
测试接口:http地址中加上后端参数访问,测试后端代码是否可以实现。
4.查看缓存问题
常见的是当前端有代码覆盖后,后面新的代码运行成功却在页面显示的是覆盖前的页面,这时在Maven面板点击clean清除缓存。
前端代码:calc.html
Document
后端实现相加:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/calc")
@RestController
public class calcController {
@RequestMapping("/sum")
public String sum(Integer num1,Integer num2){
Integer sum=num1+num2;
return "计算结果为:"+sum;
}
}
/user/login
userName = ? & password = ?
接口返回:校验成功/失败
true 密码正确
false 密码错误
/user/getUserInfo
接口返回:当前登录用户的名称
前端代码
login.html
登录页面
用户登录
用户名:
密码:
index.html
!--用户登录-->
用户登录首页
登录人:
后端代码:
package com.example.demo.controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/login")
public Boolean login(String userName, String password, HttpSession session){
//校验参数的合法性
// if(userName==null ||userName.length()==0 || password==null || 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中获取登录用户
// String username=(String) session.getAttribute("username");
// return username;
public String getUserInfo(HttpServletRequest request){
//从session中获取用户
HttpSession session= request.getSession(false);
String username=null;
if(session!=null){
username=(String)session.getAttribute("username");
}
return username;
}
}
前端页面
现在后端需要完成的是:把数据保存下来(内存、数据库....)
(1)提交留言
/message/publish
参数:MessgaeInfo(from,to,message)
返回结果:true/false
(2)查看所有留言
/message/getMessageList
参数:无
返回结果:List
后端代码:
定义一个信息类,这时我们可以使用maven自带的工具lombok自动定义set和get方法。
针对所有属性加上set和get方法,@Data放在类的外面
package com.example.demo;
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 messageInfos=new ArrayList<>();
//发布留言
@RequestMapping("/publish")
public Boolean publishMassage(MessageInfo messageInfo){
//进行参数校验
if(!StringUtils.hasLength(messageInfo.getFrom()) ||
!StringUtils.hasLength(messageInfo.getTo()) ||
!StringUtils.hasLength(messageInfo.getMessage())){
return false;
}
//添加留言
messageInfos.add(messageInfo);
return true;
}
//查看留言
@RequestMapping("/getMessageInfo")
public List getMessageInfo(){
return messageInfos;
}
}
在postman上进行测试
publish测试
getMessageInfo测试
由此可见后端代码正确。
前端交互主要代码:
留言板
输入后点击提交, 会将信息显示下方空白处
谁:
对谁:
说什么:
(1)登录
url: /user/login
参数:userName=?&password=?
响应:True/False
(2)图书列表展示
url: /book/getBookList
参数:无
响应:List
UserController
package com.lele.book;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@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.equals("admin")){}这种写法会报空指针异常
//校验账号密码是否正确
if("admin".equals(userName) && "admin".equals(password)){
//账号密码正确
//存session
session.setAttribute("userName",userName);
return true;
}
return false;
}
}
BookController
package com.lele.book;
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 getBookList(){
//1.获取图书数据
//2.对图书数据进行修改
//3.返回数据
//mock表示虚拟的假数据
List bookInfos=mockData();
for (BookInfo bookInfo:bookInfos){
if(bookInfo.getStatus()==1){
bookInfo.setStatusCN("可借阅");
}else {
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
private List mockData() {
//对已知的数据量,创建list时建议指定初始化的值
List 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?2:1);
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
BookInfo
package com.lele.book;
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;
}
测试接口是否可以正常使用
前端登录页跳转到图书列表页面主要代码:
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("用户名或密码错误!");
}
}
})
location.href = "book_list.html";
}
前端图书列表页获取到后端自动生成的图书:
function getBookList() {
$.ajax({
url:"/book/getBookList",
type:"get",
success:function(books){
var finalHtml="";
for(var book of books){
//根据每条记录拼接html,也就是一个tr
finalHtml +='' ;
finalHtml +=' ' ;
finalHtml +=''+book.id+' ' ;
finalHtml +=''+book.bookName+' ' ;
finalHtml +=''+book.author+' ' ;
finalHtml +=''+book.count+' ' ;
finalHtml +=''+book.price+' ' ;
finalHtml +=''+book.publish+' ' ;
finalHtml +=' '+book.statusCN+' ';
finalHtml +=' ';
finalHtml +=' ';
}
console.log(finalHtml);
$("tbody").html(finalHtml);
}
})
}
以上代码已经是非常简单的业务需求,但前后端代码的交互已经略显混乱。
MVC分层方式已经不足以满足现在的业务需求,取而代之的是三层架构。
(1)表现层:接收请求,返回结果
(2)业务逻辑层:业务逻辑处理
(3)数据层:处理数据,包含数据的存储、获取(增删改查)
2.在Spring中的体现
类比上面的图书管理系统:
对图书管理系统进行三层架构:
目录分层:
调整上述代码:
MVC强调数据和视图分离,将数据和数据处理分开,使用控制器对两者进行组合。
三层架构强调不同维度的数据处理:将交互界面、业务处理和数据库的逻辑分开。
两者可以互相转换。两者的目的都是:解耦、分层、代码复用。