【SpringBoot】从零开始全面解析SpringMVC (三)

【SpringBoot】从零开始全面解析SpringMVC (三)
在这里插入图片描述
本篇博客给大家带来的是SpringBoot的知识点, 本篇是SpringBoot入门, 介绍SpringMVC相关知识.
🐎文章专栏: JavaEE进阶
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .

王子,公主请阅🚀

要开心

要快乐

顺便进步

1. 综合练习

1.1 留言板

在这里插入图片描述


需求:
界面如上图所示👆
1. 输入留言信息, 点击提交. 后端把数据存储起来.
2. 页面展示输入得表白墙的信息.

1.1.1 准备工作

码云链接: 薯条不要番茄酱

在这里插入图片描述

1.1.2 约定前后端交互接口

Ⅰ 发布留言
url : /message/publish .
param(参数) : from,to,say .
return : true / false .

Ⅱ 查询留言
url : /message/getList.
param : 无
return : form 对 to 说了 say

1.1.3 实现服务器代码:


Ⅰ 写代码之前,介绍一个新的工具包 lombok.

Lombok是一个Java工具库,通过添加注解的方式简化Java的开发.


① 引入依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>


② 使用

lombok 通过一些注解的方式, 可以帮助我们消除一些冗长代码, 使代码看起来简洁一些. 就比如:上面写的 Student 对象, 无需自己写 get , set , toString方法. 只需写一个注解 @Data就可以了.

importlombok.Data;@DatapublicclassStudent{privateString name;privateInteger id;privateint age;}


③ 原理解释

加了@Data 注解之后, Idea 反编译的class文件.

在这里插入图片描述



这不是真正的字节码文件, 而是Idea根据字节码进行反编译后的文件.
反编译是将可执行的程序代码转换为某种形式的高级编程语言, 使其具有更易读的格式. 反编译是一种逆向工程,它的作用与编译器的作用相反.

在这里插入图片描述



④ 更多使用

如果觉得@Data生成的方法太多, lombok 也提供了一些更精细粒度的注解.

在这里插入图片描述




Ⅱ 更快捷引入依赖

① 安装插件EditStarter, 重启Idea.

在这里插入图片描述



② 在pom.xml 文件中, 单击右键, 选择Generate, 操作如下图所示

在这里插入图片描述



③ 进入 Edit Starters的编辑界面, 添加对应依赖即可.

在这里插入图片描述



Ⅲ 实现服务器代码

定义留言对象

importlombok.Data;@DatapublicclassMessageInfo{privateString from;privateStringto;privateString say;}


创建 MessageController 类

importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.ArrayList;importjava.util.List;@RequestMapping("/message")@RestControllerpublicclassMessageController{List<MessageInfo> messageInfos =newArrayList<>();@RequestMapping("/publish")publicBooleanpublish(MessageInfo messageInfo){//校验信息if(!StringUtils.hasLength(messageInfo.getFrom())||!StringUtils.hasLength(messageInfo.getTo())||!StringUtils.hasLength(messageInfo.getSay())){returnfalse;}//把信息存起来方便下一个方法获取 messageInfos.add(messageInfo);returntrue;}@RequestMapping("/getList")publicList<MessageInfo>getList(){return messageInfos;}}


前端页面代码

<!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> function submit(){ $.ajax({ url:"/message/publish", type:"get", data:{ from: $("#from").val(),to: $("#to").val(), say: $("#say").val()},//http响应成功 success:function(result){if(result ==false){alert("输入不合法");}else{//展示信息//1. 构造节点var divE ="<div>"+from+"对"+to+"说:"+ say +"</div>";//2. 把节点添加到页面上 $(".container").append(divE);//3. 清空输入框的值 $("#from").val(""); $("#to").val(""); $("#say").val("");}}});}</script></body></html>

1.2 图书管理系统


需求:
1. 登录: 用户输入账号,密码完成登录功能.
2. 列表展示: 展示图书.

在这里插入图片描述


在这里插入图片描述

1.2.1 准备工作


创建新项目,引入依赖.

在这里插入图片描述


将前端代码复制到 static 目录下.

在这里插入图片描述

1.2.2 约定前后端交互接口

先实现其中的两个功能: 用户登录 和 图书列表展示.

需求分析:

1. 用户登录
url : /user/login
param : userName 和 password
return : String(提示)


2. 图书列表展示 1. url : /book/getBookList
2. param : 无
3. return : 图书列表

1.2.3 服务器代码


创建图书类

importlombok.Data;importjava.math.BigDecimal;@DatapublicclassBookInfo{privateInteger id;privateString bookName;privateString author;privateInteger num;privateBigDecimal price;privateString publishName;privateInteger status;//对于可枚举的属性(以后可能会改的属性),通常用数字表示: 1-可借阅, 2-不可借阅privateString statusCN;}


创建UserController, 实现登录验证接口.

importjakarta.servlet.http.HttpSession;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/user")@RestControllerpublicclassUserController{@RequestMapping("/login")publicStringlogin(String userName,String password,HttpSession session){//校验用户信息是否合法.if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){return"用户名或密码为空";}//判断用户名和密码是否正确//理论上应该从数据库中获取, 但是目前还没学习 mybatis, 所以先这么写.if(!"admin".equals(userName)||!"admin".equals(password)){return"用户名或密码错误";} session.setAttribute("userName",userName);return"";}}


创建BookController, 获取图书列表

importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.math.BigDecimal;importjava.util.ArrayList;importjava.util.List;@RequestMapping("/book")@RestControllerpublicclassBookController{@RequestMapping("/getBookList")publicList<BookInfo>getBookList(){List<BookInfo> bookInfos =newArrayList<>();//mock(模拟) 数据for(int i =1; i <=15; i++){BookInfo bookInfo =newBookInfo(); bookInfo.setId(i); bookInfo.setBookName("图书"+i); bookInfo.setAuthor("作者"+i); bookInfo.setNum(i*2+1); bookInfo.setPrice(newBigDecimal(i*3)); bookInfo.setPublishName("出版社"+i);if(i %5==0){ bookInfo.setStatus(2); bookInfo.setStatusCN("不可借阅");}else{ bookInfo.setStatus(1); bookInfo.setStatusCN("可借阅");} bookInfos.add(bookInfo);}return bookInfos;}}

调整前端页面代码


登录页面:

<!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 !=""){alert("用户名或密码错误,请重新输入");}else{ location.href ="book_list.html";}}});}</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></tbody></table><div class="demo"><ul id="pageContainer"class="pagination justify-content-center"></ul></div><script>getBookList(); function getBookList(){ $.ajax({ url:"/book/getBookList", type:"get", success:function(books){var finnalHtml ="";for(var book of books){ finnalHtml +='<tr>'; finnalHtml +='<td><input type="checkbox" name="selectBook" value="1"></td>'; finnalHtml +='<td>'+book.id+'</td>'; finnalHtml +='<td>'+book.bookName+'</td>'; finnalHtml +='<td>'+book.author+'</td>'; finnalHtml +='<td>'+book.num+'</td>'; finnalHtml +='<td>'+book.price+'</td>'; finnalHtml +='<td>'+book.publishName+'</td>'; finnalHtml +='<td>'+book.statusCN+'</td>'; finnalHtml +='<td>'; finnalHtml +='<div>'; finnalHtml +='<a href="book_update.html?bookId='+book.id+'">修改</a>'; finnalHtml +='<a href="javascript:void(0)" onclick="deleteBook('+book.id+')">删除</a>'; finnalHtml +='</div>'; finnalHtml +='</td>'; finnalHtml +='</tr>';} $("tbody").html(finnalHtml);}});}//翻页信息 $("#pageContainer").jqPaginator({ totalCounts:100,//总记录数 pageSize:10,//每页的个数 visiblePages:5,//可视页数 currentPage:1,//当前页码 first:'<li><a>首页</a></li>', prev:'<li><a href="javascript:void(0);">上一页<\/a><\/li>', next:'<li><a href="javascript:void(0);">下一页<\/a><\/li>', last:'<li><a href="javascript:void(0);">最后一页<\/a><\/li>', page:'<li><a 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){//获取复选框的idvar ids =[]; $("input:checkbox[name='selectBook']:checked").each(function (){ ids.push($(this).val());}); console.log(ids);alert("批量删除成功");}}</script></div></body></html>

2. 应用分层


通过上面的练习, 我们学习了Spring MVC简单功能的开发, 但是我们也发现了一些问题。
目前我们程序的代码有点"杂乱", 然而当前只是"一点点功能"的开发. 如果我们把整个项目功能完成代码会更加的"杂乱无章"(文件乱, 代码内容也乱)。

基于此, 咱们接下来学习应用分层.

2.1 分层结构介绍


Ⅰ 什么是应用分层?

应用分层 是一种软件开发设计思想, 它将应用程序分成N个层次, 这N个层次分别负责各自的职责, 多个层次之间协同提供完整的功能. 根据项目的复杂度, 把项目分成三层, 四层或者更多层.
常见的MVC设计模式, 就是应用分层的一种具体体现.

Ⅱ 应用分层的目的

在最开始的时候,为了让项目快速上线,我们通常是不考虑分层的. 但是随着业务越来越复杂,大量的
代码混在一起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动一处就牵动全局的问题。 所以学习对项进行分层就是我们程序员的必修课了.

Ⅲ 如何分层

“MVC” 就是把整体的系统分成了 Model(模型), View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔开,并且通过控制器连接起来,很好地实现
了表现和逻辑的解耦,是一种标准的软件分层架构。

在这里插入图片描述



目前更主流的开发方式是 “前后端分离” 的方式, 后端开发工程师不再需要关注前端的实现, 对于Java后端开发者, 又有了一种新的分层架构: 把整体架构分为表现层、业务逻辑层和数据层. 这种分层方式也称之为"三层架构".

1. 表现层:就是展示数据结果和接受用户指令的,是最靠近用户的一层;
2. 业务逻辑层:负责处理业务逻辑, 里面有复杂业务的具体实现;
3. 数据层:负责存储和管理与应用程序相关的数据。


按照上面的层次划分, Spring MVC 站在后端开发人员的角度上, 也进行了支持, 把上面的代码划分为三个部分:

在这里插入图片描述


请求处理、响应数据:负责,接收页面的请求,给页面响应数据.
逻辑处理: 负责业务逻辑处理的代码.
数据访问: 负责业务数据的维护操作,包括增、删、改、查等操作.


这三个部分, 在Spring的实现中, 均有体现:

在这里插入图片描述



Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
Service:业务逻辑层。处理具体的业务逻辑。
Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

2.2 代码重构

使用上面的分层思想, 来对代码进行改造。

先创建对应的包路径, 并把代码移到对应的目录

com.fhao.book.controller
com.fhao.book.service
com.fhao.book.dao
com.fhao.book.model

在这里插入图片描述


在dao 目录下创建 BookDao文件 在service 目录下创建 BookService文件:

在这里插入图片描述

将 BookController 中的代码改写成👇:

@RequestMapping("/getBookList")publicList<BookInfo>getBookList(){BookService bookService =newBookService();return bookService.getBookList();}


BookDao文件 中的代码:

publicList<BookInfo>mockData(){//理论上该方法应该从数据库获取, 此处先mock 数据.List<BookInfo> bookInfos =newArrayList<>();for(int i =1; i <=15; i++){BookInfo bookInfo =newBookInfo(); bookInfo.setId(i); bookInfo.setBookName("图书"+i); bookInfo.setAuthor("作者"+i); bookInfo.setNum(i*2+1); bookInfo.setPrice(newBigDecimal(i*3)); bookInfo.setPublishName("出版社"+i);if(i %5==0){ bookInfo.setStatus(2); bookInfo.setStatusCN("不可借阅");}else{ bookInfo.setStatus(1); bookInfo.setStatusCN("可借阅");} bookInfos.add(bookInfo);}return bookInfos;}


BookService文件 中的代码

publicList<BookInfo>getBookList(){BookDao bookDao =newBookDao();List<BookInfo> bookInfos = bookDao.mockData();for(BookInfo bookInfo : bookInfos){if(bookInfo.getStatus()==2){ bookInfo.setStatusCN("不可借阅");}else{ bookInfo.setStatusCN("可借阅");}}return bookInfos;}

2.3 应用分层的好处


1. 降低层与层之间的依赖, 结构更加的明确, 利于各层逻辑的复用.
2. 开发人员可以只关注整个结构中的其中某一层, 极大地降低了维护成本和维护时间.
3. 可以很容易的用新的实现来替换原有层次的实现.
4. 有利于标准化.


3. 总结

3.1 注解


学习Spring MVC, 其实就是学习各种Web开发需要用的到注解。

a. @RequestMapping: 路由映射

b. @RequestParam: 后端参数重命名

c. @RequestBody: 接收JSON类型的参数

d. @PathVariable: 接收路径参数

e. @RequestPart: 上传文件

f. @ResponseBody: 返回数据

g. @CookieValue: 从Cookie中获取值

h. @SessionAttribute: 从Session中获取值

i. @RequestHeader: 从Header中获取值

j. @Controller: 定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理. 默认返回
视图.

k. @RestController: @ResponseBody + @Controller 返回数据


Cookie 和Session都是会话机制, Cookie是客户端机制, Session是服务端机制. 二者通过 SessionId来关联. Spring MVC内置 HttpServletRequest 和HttpServletResponse 两个对象. 需要使用时, 直接在方法中添加对应参数即可, Cookie 和 Session 可以从HttpServletRequest 中来获取, 也可以直接使用 HttpServletResponse 设置Http响应状态码.




本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊

Read more

Stable Diffusion的3个替代方案

Stable Diffusion的3个替代方案

Stable Diffusion 虽然不再像2022-2023年那样热门,但仍然是最重要的开源权重图像模型之一。它允许用户使用自己的自定义数据集对模型进行微调,从而获得对相似度、艺术风格或特定角色细节的精确控制。但这需要一定的模型训练知识,设置和微调过程并不简单,训练时间也取决于训练数据的大小。 1、PixAI PixAI 是一个专门针对动漫风格和高度风格化数字艺术作品进行优化的AI图像生成平台。平台提供数百个社区微调模型和一套强大的工具,帮助你轻松将创意想法转化为现实。 平台专为动漫主题视觉而设计,既作为创作工具,也作为社交网络,允许你从头创作新作品或"混音"其他社区成员生成的图像。 最有趣的是能够轻松训练自己的 LoRA (Low-Rank Adaptation)。过去这是一项复杂的任务,现在只需上传训练图像,分配触发名称,等待平台烘焙自定义图像模型即可。 使用现有的风格化模型,只需简单的提示词就能实现精美的动漫风格图像,无需明确告诉AI需要特定的风格、色调、着色等。 2、ChatGPT ChatGPT 是目前最受欢迎的通用聊天应用,其图像生成功能由 GPT-Im

By Ne0inhk
近五年体内微/纳米机器人赋能肿瘤精准治疗综述:以 GBM 为重点

近五年体内微/纳米机器人赋能肿瘤精准治疗综述:以 GBM 为重点

摘要 实体瘤治疗长期受制于递送效率低、肿瘤组织渗透不足以及免疫抑制与耐药等问题。传统纳米药物多依赖被动累积与扩散,难以在肿瘤内部形成均匀有效的药物浓度分布。2021–2025 年,体内微/纳米机器人(包括外场驱动微型机器人、自驱动纳米马达以及生物混合机器人)围绕“运动能力”形成了三条相互收敛的技术路线: 其一,通过磁驱、声驱、光/化学自驱等方式实现运动增强递药与深层渗透,将治疗从“被动到达”推进到“主动进入”; 其二,与免疫治疗深度融合,实现原位免疫唤醒与肿瘤微环境重塑; 其三,针对胶质母细胞瘤(glioblastoma, GBM)等难治肿瘤,研究趋势转向“跨屏障递送(BBB/BBTB)+ 成像/外场闭环操控 + 时空可控释放”的系统工程。 本文围绕“运动—分布—疗效”的因果链条,总结 2021–2025 年代表性研究与关键评价指标,讨论临床转化所需的安全性、

By Ne0inhk
Vivado:使用 ILA 进行在线调试

Vivado:使用 ILA 进行在线调试

目录 一、ILA介绍 二、ILA使用步骤 (1)设计部分 (2)调用ILA IP核 (3)例化ILA IP核 (4)编译综合 三、ILA在线调试 (1)手动运行 (2)运行触发条件 (3)连续触发 一、ILA介绍         Vivado中的ILA(Integrated Logic Analyzer)即集成逻辑分析仪,是一种在线调试工具。ILA允许用户在FPGA上执行系统内的调试,通过实时抓取FPGA内部数字信号的波形,帮助我们分析逻辑错误的原因,从而更有效地进行debug。类似于Quartus中的SignalTap II,也类似于片上的逻辑分析仪。         相较于编写testbench仿真文件仿真debug的方式,使用ILA调试的方法不写tb仿真文件从而节省时间,可直接上板调试并查看波形。 二、ILA使用步骤         ILA常以IP核的方式调用,可以在IP Catalog中搜索ILA,找到该IP核后进行配置。 配置选项包括:样本数据深度、探针数量、

By Ne0inhk
AiOnly大模型深度测评:调用GPT-5 API+RAG知识库,快速构建智能客服机器人

AiOnly大模型深度测评:调用GPT-5 API+RAG知识库,快速构建智能客服机器人

声明:本测试报告系作者基于个人兴趣及使用场景开展的非专业测评,测试过程中所涉及的方法、数据及结论均为个人观点,不代表任何官方立场或行业标准。 引言 AI 技术加速渗透各行各业的今天,你是否也面临这样的困境:想调用 GPT-5、Claude4.5等顶尖模型却被海外注册、跨平台适配搞得焦头烂额?想快速搭建智能客服、内容生成工具,却因模型接口差异、成本不可控而望而却步?或是作为中小团队,既想享受 AI 红利,又受限于技术门槛和预算压力? AiOnly平台的出现,正是为了打破这些壁垒。 本文将从实战角度出发,带你全方位解锁这个「全球顶尖大模型 MaaS 平台」:从 5 分钟完成注册到 API 密钥创建,从单模型调用到融合 RAG 知识库的智能体开发,然后手把手教你在 Windows 环境部署一个日均成本不足 0.5 元的电商客服机器人。无论你是 AI 开发者、企业运营者,还是想低成本尝试 AI

By Ne0inhk