基于Spring MVC的前后端交互案例及应用分层的实现

目录

分析程序报错的步骤

案例

一.加法计算器

二.实现用户登录

1.登录接口

2.获取用户的登录信息

三.留言板

1.接口定义

2.完成后端代码

3.测试后端代码

四.图书管理系统

1.定义接口

2.后端代码

3.测试后端代码

4.前端交互代码

应用分层

1.三层架构


分析程序报错的步骤

1.定位是前端还是后端:通过日志

1)前端:F12、看控制台

2)后端:接口、控制台

2.判断请求是否到达后端

1)后端代码在相应方法的第一行,通过打印一些标记的字符串来判断。运行后如果没有打印内容则请求没有到达后端

2)抓包查看访问的接口是否正确

3.当感觉前端代码没有错,后端却接收不到请求

测试接口:http地址中加上后端参数访问,测试后端代码是否可以实现。

4.查看缓存问题

常见的是当前端有代码覆盖后,后面新的代码运行成功却在页面显示的是覆盖前的页面,这时在Maven面板点击clean清除缓存。

案例

一.加法计算器

前端代码:calc.html

<!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>

后端实现相加:

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;}
}

二.实现用户登录

1.登录接口

/user/login

userName = ? & password = ?

接口返回:校验成功/失败

true   密码正确

false  密码错误

2.获取用户的登录信息

/user/getUserInfo

接口返回:当前登录用户的名称

前端代码

login.html

<!--用户登录-->
<!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() {// 测试日志 检测前端请求是否能发出(onlick)的时候console.log("登录...")$.ajax({url:"/user/login",type:"post",data:{"userName":$("#userName").val(),"password":$("#password").val()},success:function(result){if(result){location.href ="/index2.html";}else{alert("密码错误");}}});}</script>
</body></html>

index.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:"post",success:function(userName){$("#loginUser").text(userName);}})
</script>
</body></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)){//设置sessionsession.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.接口定义

(1)提交留言 

/message/publish

参数:MessgaeInfo(from,to,message)

返回结果:true/false

(2)查看所有留言

/message/getMessageList

参数:无

返回结果:List<MessageInfo>

后端代码

定义一个信息类,这时我们可以使用maven自带的工具lombok自动定义set和get方法。

针对所有属性加上set和get方法,@Data放在类的外面

2.完成后端代码

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<MessageInfo> 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<MessageInfo> getMessageInfo(){return messageInfos;}
}

3.测试后端代码

在postman上进行测试

publish测试

getMessageInfo测试

由此可见后端代码正确。

前端交互主要代码:

<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) {//2. 构造节点var divE = "<div>" + m.from + "对" + m.to + "说:" + m.message + "</div>";//3. 把节点添加到页面上$(".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: {"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>

四.图书管理系统

1.定义接口

(1)登录

url:  /user/login

参数:userName=?&password=?

响应:True/False

(2)图书列表展示

url: /book/getBookList

参数:无

响应:List<BookInfo>

2.后端代码

  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)){//账号密码正确//存sessionsession.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<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?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;}

3.测试后端代码

测试接口是否可以正常使用

4.前端交互代码

前端登录页跳转到图书列表页面主要代码:

 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,也就是一个trfinalHtml +='<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.count+'</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>';finalHtml +='</td></tr>';}console.log(finalHtml);$("tbody").html(finalHtml);}})}

应用分层

以上代码已经是非常简单的业务需求,但前后端代码的交互已经略显混乱。

MVC分层方式已经不足以满足现在的业务需求,取而代之的是三层架构

1.三层架构

(1)表现层:接收请求,返回结果

(2)业务逻辑层:业务逻辑处理

(3)数据层:处理数据,包含数据的存储、获取(增删改查)

2.在Spring中的体现

类比上面的图书管理系统:

对图书管理系统进行三层架构:

目录分层:

调整上述代码:

MVC强调数据和视图分离,将数据和数据处理分开,使用控制器对两者进行组合。

三层架构强调不同维度的数据处理:将交互界面、业务处理和数据库的逻辑分开。

两者可以互相转换。两者的目的都是:解耦、分层、代码复用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189283.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT Creator 保存(Ctrl+S)时,会将Tab制表符转换为空格

今天在写makefile文件时&#xff0c;发现QT Creator 保存(CtrlS)时&#xff0c;会将Tab制表符转换为空格&#xff0c;之前没有发现&#xff0c;略坑&#xff0c;官网上也有说明&#xff0c;点这里 简单来说&#xff0c;解决办法如下 依次点击&#xff1a;Tools ->Options-&g…

JPA数据源Oracle异常记录

代码执行异常 ObjectOptimisticLockingFailureException org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleSta…

Linux 文件管理

内容概述 1 文件系统目录结构 存放的是内存中正在运行的系统状态信息&#xff0c;数据不在硬盘而是在内存中 echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all1.1 文件系统的目录结构 Linux 操作系统 ext / xfs 文件系统是区分大小写&#xff0c;大小写敏感 Linux的文件…

MySQL导出ER图为图片或PDF

目录 1、Navicat 生成ER图 1、选择数据库&#xff0c;逆向数据库到模型 2、查看ER图 3、导出ER图 2、使用MySQL官方工具&#xff1a;MySQL Workbench 1、首先连接MySQL数据库 2、点击Database&#xff0c;选择Reverse Engineer 3、填写数据库信息&#xff0c;点Next …

【鸿蒙应用ArkTS开发系列】-自定义底部菜单列表弹窗

文章目录 前言创建Demo工程创建dialog 文件夹创建ListMenu 接口创建自定义弹窗 ListMenuDialog使用自定义弹窗 打包测试效果演示默认效果菜单带图标效果设置文本颜色效果不同文本颜色效果无标题效果 前言 上一篇文章中我们实现了选择图片、选择文件、拍照的功能 。 链接在这里…

每日一练2023.12.1——输出GPLT【PTA】

题目链接&#xff1a;L1-023 输出GPLT 题目要求&#xff1a; 给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序&#xff0c;按GPLTGPLT....这样的顺序输出&#xff0c;并忽略其它字符。当然&#xff0c;四种字符&#xff08;不区分大小写&#x…

对小程序的初了解

WXML和HTML的区别 标签名称不同 HTML&#xff1a;div、a、span、img WXML&#xff1a;view、text、image、navigator 属性节点不同 <a href"#">超链接</a> <navigator url"/pages/home/home"></navigator> 提供了类似vue的…

计算机视觉(OpenCV+TensorFlow)

计算机视觉&#xff08;OpenCVTensorFlow&#xff09; 文章目录 计算机视觉&#xff08;OpenCVTensorFlow&#xff09;前言7. 图像直方图绘制直方图绘制直方图有两种方式&#xff1a; 掩膜 8. 直方图均衡化直方图均衡化的介绍直方图均衡化的步骤自适应直方图均衡化 9. 图像转换…

SAP_ABAP_编程基础_数据集_创建并填充摘录数据集 / 处理摘录数据集

SAP ABAP 顾问&#xff08;开发工程师&#xff09;能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读494次。目标&#xff1a;基于对SAP abap 顾问能力模型的梳理&#xff0c;给一年左右经验的abaper 快速成长为三年经验提供超级燃料&#xff01;https://blog.csdn.net/j…

webshell之自建漏洞免杀

今天主要讲解&#xff0c;如何利用通用漏洞来进行命令执行&#xff0c;从而达到免杀效果 常规反序列化免杀 这种方式就相当于直接触发提供一个反序列化漏洞入口&#xff0c;但是能否被利用&#xff0c;还是在于服务端本身是否存在反序列化漏洞&#xff0c;下面给了一个例子&a…

基于机器学习的笔记本电脑导购系统

目 录 中英文摘要 第一章 概述 1 1.1 课题开发背景及意义 1 1.2 课题研究现状 2 1.3 课题主要研究内容 3 第二章 需求分析 4 2.1 功能需求分析 4 2.2 可行性分析 10 2.3 流程分析 11 2.4 数据流图 13 2.5 性能需求分析 15 第三章 开发技术及工具 16 3.1 系统开发模式技术 16 3…

《凤凰项目》读书笔记

文章目录 一、书名和作者二、书籍概览2.1 主要论点和结构2.2 目标读者和应用场景 三、核心观点与主题3.1 DevOps的核心原则与文化变革3.2 持续交付与自动化3.3 变更管理与风险控制3.4 关键绩效指标与持续改进 四、亮点与启发4.1 最有影响的观点4.2 对个人专业发展的启示 五、批…

【Linux--进程控制】

目录 一、进程等待1.1进程等待方法1.2获取子进程status 二、进程替换2.1单进程版本--最简单得程序替换2.2 进程替换得原理2.3 多进程版本--验证各种程序替换接口2.4 总结 一、进程等待 1.1进程等待方法 问题1&#xff1a;进程等待是什么&#xff1f; 通过系统调用wait/waitpi…

Java 定时任务

Java 定时任务 为什么需要定时任务&#xff1f; 我们来看一下几个非常常见的业务场景&#xff1a; 某系统凌晨 1 点要进行数据备份。某电商平台&#xff0c;用户下单半个小时未支付的情况下需要自动取消订单。某媒体聚合平台&#xff0c;每 10 分钟动态抓取某某网站的数据为…

五、关闭三台虚拟机的防火墙和Selinux

目录 1、关闭每台虚拟机的防火墙 2、关闭每台虚拟机的Selinux 2.1 什么是SELinux

使用SpringBoot和ZXing实现二维码生成与解析

一、ZXing简介 ZXing是一个开源的&#xff0c;用Java实现的多种格式的1D/2D条码图像处理库。它包含了用于解析多种格式的1D/2D条形码的工具类&#xff0c;目标是能够对QR编码&#xff0c;Data Matrix, UPC的1D条形码进行解码。在二维码编制上&#xff0c;ZXing巧妙地利用构成计…

系列十四、SpringBoot的jar包可以直接运行原理分析

一、普通jar包运行 vs SpringBoot jar包运行 1.1、普通jar包运行 general-test-1.0-SNAPSHOT.jar是位于D盘的一个普通的jar包&#xff0c;是idea中一个普通的maven项目通过package打包生成&#xff0c;为了方便测试我把它拷贝到D盘了。 java -jar general-test-1.0-SNAPSHOT.j…

springboot虚拟请求——测试

springboot虚拟请求 表现层测试 web环境模拟测试 虚拟请求状态匹配——执行状态的匹配 Testvoid testStatus(Autowired MockMvc mvc) throws Exception { // //http://localhost:8080/books// 创建一个虚拟请求&#xff0c;当前访问的是booksMockHttpServletRequestBui…

不会代码(零基础)学语音开发(学习工具)

学习&#xff0c;要选择适合自己的&#xff0c;好的学习工具至关重要。就像读书&#xff0c;要读好书一样。 自己不会选&#xff0c;可以参考前辈&#xff0c;找chatgpt等来帮忙。充分利用好周边的资源。 秉承着GPT和前辈们的经验之谈&#xff0c;开始选择语音开发产品&#…

localStorage 和sessionStorage

localStorage 和 sessionStorage 是浏览器提供的两种客户端存储数据的方式&#xff1a; 生命周期&#xff1a; localStorage&#xff1a; 存储在 localStorage 中的数据在浏览器关闭后仍然保留&#xff0c;直到被显式删除或浏览器清除缓存。sessionStorage&#xff1a; 存储在 …