[Spring] Spring Web MVC案例实战
创始人
2024-12-29 05:04:47
0

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. 加法计算器
    • 1.1 约定前后端交互的接口(接口文档)
    • 1.2 前端代码
    • 1.3 后端代码
  • 2. 用户登录
    • 2.1 接口文档
    • 2.2 前端代码
      • 2.2.1 登录页面
      • 2.2.2 首页
    • 2.3 后端代码
      • 2.3.1 登录页面
      • 2.3.2 主页
  • 3. 留言板
    • 3.1 接口文档
    • 3.2 前端代码
    • 3.3 后端代码
      • 3.3.1 lombok介绍
  • 4. 图书管理系统
    • 4.1 接口文档
    • 4.2 前端代码
    • 4.3 后端代码
  • 5. 应用分层
    • 4.1 介绍
    • 4.2 具体在项目中的体现

1. 加法计算器

需求:输入两个整数,点击"点击相加"按钮,显示计算结果.

1.1 约定前后端交互的接口(接口文档)

这是Web开发中的关键一环.接口又叫API,我们一般讲到的API或者接口,指的都是同一个东西.如今我们的开发一般采用前后端分离的方式,所以我们在开发之前,前端开发人员和后端开发人员会约定好前后端交互的方式.我们一般会把约定的内容写在文档上,就是"接口文档".接口文档可以理解为是应用程序中的"操作说明书".
在项目开发之前.我们需要先更具需求拟写接口文档,前后端必须都准寻接口文档中的标准.**接口文档通常由服务提供方来写,有服务使用方确认,也就是客户端.**关于接口文档怎么写,每个公司有不同的标准,一般是需求分析和接口定义(接口名称,URL),传递参数,返回参数下面我们来拟写这个案例的简单接口文档:

需求分析: 输入两个整数,点击"点击相加"按钮,显示计算结果.
接口定义:

请求路径:calc/sum, 请求方式:GET/POST, 接口描述:计算两个整数相加 

请求参数:

参数名类型是否必须备注
num1Integer参与计算的第⼀个数
num2Integer参与计算的第⼆个数
响应数据:
Content-Type: text/html 响应内容:计算机计算的结果 

1.2 前端代码

首先,我们需要准备前端的代码.把前端的代码calc.html放在项目的Static目录中.
在这里插入图片描述

                 Document        

计算器

数字1:
数字2:

1.3 后端代码

package com.example.demo;  import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  @RequestMapping("/calc") @RestController public class Calc {     @RequestMapping("/sum")     public String sum(Integer num1,Integer num2){         Integer sum = num1 + num2;         return "

加和结果

" + sum; } }

首先使用查询字符串来给参数传递值来测试后端代码的正确性.后端代码的逻辑没有问题.
在这里插入图片描述
之后我们连带前端代码一起运行起来.
在这里插入图片描述
在这里插入图片描述

如果前后端交互的时候出现了一些问题的时候,我们一般按照下面这样的步骤来解决:

  1. 首先清理前端(Ctrl+f5刷新页面)缓存,和后端(pom:clean)缓存.
  2. 首先看错误日志
  3. 确认后端接口是否有问题(可以通过浏览器或者Postman访问)
  4. 前端请求时,Fiddler抓包或者Debug,观察接参数或者URL是否有问题.

2. 用户登录

需求:用户输入账号和密码,后端进行校验密码是否正确.

  1. 如果正确,跳转到首页,首页显示当前登录用户的用户名
  2. 如果错误,前端进行用户告知.
  3. 后续在访问首页,可以获取到登录用户信息.

2.1 接口文档

需求分析:

用户输入账号和密码,后端进行校验密码是否正确.

  1. 如果正确,跳转到首页,首页显示当前登录用户的用户名
  2. 如果错误,前端进行用户告知.
  3. 后续在访问首页,可以获取到登录用户信息.
  • 登录页面

    接口定义:

    请求路径: /user/login 请求方式: POST 接口描述: 校验账号和密码的正确性. 

    请求参数:

    参数名类型是否必须备注
    userNameString校验的账号
    passwordString校验的密码

    响应数据:

    Content-Type : text/html 响应内容:  账号密码正确:true 账号密码错误:false 
  • 主页
    接口定义:

    请求路径: /user/getLoginuser 请求方式: GET 接口描述: 显示当前登录用户的主页,主页上显示用户名. 

    请求参数:

    响应数据:

    Content-Type:text/html 响应内容: 登录的用户名. 

2.2 前端代码

对于前端而言,点击登录按钮的时候,需要把用户传递的信息传递到后端进行校验,后端校验成功之后,则跳转到首页:index.html,后端校验失败之后,直接弹窗.

2.2.1 登录页面

         登录页面      

用户登录

用户名:
密码:
  • 这里我们使用ajax来进行信息传递,不用form表单的原因,是为了在输入错误的时候,不让页面发生跳转,如果使用form表单的话,页面一定会发生跳转.再者,因为ajax是异步调用的,在ajax的头部把信息先留下,之后再说对信息如何处理以及如何做.

何为异步?比如我们去街道处办事,我们需要先提交我们的资料,但是给我办事的那个人不在,同步操作就是一直等,等到那个人来,异步就是先把资料留下,先回家,等事情办好之后,给你打电话.

  • success: function (result)其中的success表示的是接口返回结果的成功和失败,而不是业务结果返回true或者是false.

比如我们去银行办理业务,有三种可能:

  1. 银行没开门
  2. 忘记带身份证了,业务办理失败
  3. 证件携带齐全,业务办理成功
    第一种就是接口返回了错误信息,第二种就是业务逻辑返回false,第三种就是业务逻辑返回true.
  • 页面跳转的三种方式:
  1. window.location.href=index.html
  2. window.location.assign(“index.html”)
  3. window.location.replace(“index.html”)
    我们一般把window省略.1,2是等价的,在进入新的页面之后,都可以回退回上一个页面,而3无法回退到上一个页面.

2.2.2 首页

                       用户登录首页        登录人:                

2.3 后端代码

2.3.1 登录页面

package com.example.demo;  import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  @RequestMapping("/user") @RestController public class Login {     @RequestMapping("/login")     public Boolean login(String userName, String password, HttpSession session){         //确保输入的密码和账号都不为空         //也为了保证前端传递信息成功,不会传递一个null过来         if (!StringUtils.hasLength(userName) ||                 !StringUtils.hasLength(password)){             return false;         }         if (!"zhangsan".equals(userName) ||                 ! "123456".equals(password)){             return false;         }         //密码和账号都正确,设置session         session.setAttribute("userName",userName);         return true;     } }  

其中StringUtils.hasLength()方法是Spring中提供的一个工具方法,判断字符串是否有值.字符串为null或者是""时,返回false,其他返回true.

public static boolean hasLength(@Nullable String str) {     return str != null && !str.isEmpty(); } 

2.3.2 主页

package com.example.demo;  import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  @RequestMapping("/user") @RestController public class GetUserLogin {     @RequestMapping("/getUserLogin")     public String getUserLogin(HttpSession httpSession){         //从session中获取用户名         String userName = (String) httpSession.getAttribute("userName");         if (StringUtils.hasLength(userName)){//确保userName有值             return userName;         }         return null;     } } 

运行代码:
在这里插入图片描述
登录成功:
在这里插入图片描述
登录失败:
在这里插入图片描述

3. 留言板

3.1 接口文档

需求分析:

  1. 提交留言:用户输⼊留言信息之后,后端需要把留言信息保存起来
  2. 展示留言:页面展示时,需要从后端获取到所有的留言信息

接口定义:

  1. 获取全部留言
    全部留言信息,我们用List来表示,可以用JSON来描述这个List数据.
    请求:
    GET /message/getList 
    响应:JSON格式
    [  {  "from": "黑猫",  "to": "白猫",  "message": "喵" },{  "from": "黑狗",  "to": "白狗",  "message": "汪"  },  //... ] 
    浏览器给服务器发送⼀个GET /message/getList 这样的请求,就能返回当前⼀共有哪些留言记录.结果以json的格式返回过来.
  2. 发表新留言
    请求:body也为JSON格式.
    POST /message/publish {  "from": "黑猫",  "to": "白猫",  "message": "喵" } 响应:JSON格式. {  ok: 1 } 
    我们期望浏览器给服务器发送⼀个POST /message/publish 这样的请求,就能把当前的留言提交给服务器.

3.2 前端代码

                  留言板             

留言板

输入后点击提交, 会将信息显示下方空白处

谁:
对谁:
说什么:

3.3 后端代码

package com.example.demo;  import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestBody; 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 MessageWall {     public List messageInfoList = new ArrayList<>();     @RequestMapping("/publish")     public Boolean messageController(@RequestBody MessageInfo messageInfo){         System.out.println(messageInfo);//打印日志         if (StringUtils.hasLength(messageInfo.from) &&         StringUtils.hasLength(messageInfo.to) &&         StringUtils.hasLength(messageInfo.say)){             messageInfoList.add(messageInfo);             return true;//都有长度,添加成功,返回true         }         //添加失败,返回false         return false;     }     @RequestMapping("/getList")     public List getList(){         return messageInfoList;     } }  
package com.example.demo;  import lombok.Data;  @Data public class MessageInfo {     public String from;     public String to;     public String say; }  

3.3.1 lombok介绍

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

  1. 引入依赖
     org.projectlombok     lombok     true  
  1. 使用
    lombok通过使用一些注释的方式,可以帮我们消除一些冗长的代码,让代码看起来更简洁.
    比如我们之前的Person对象就可以简化为:
package com.example.demo;  import lombok.Data;  @Data public class Person {     public String name;     public int age;     public String sex; } 

其中,@Data注解会帮助我们自动⼀些方法,包含getter/setter,equals,toString等.
3. 更多使用方法
@Data生成的方法太多,lombok页为我们提供了一些颗粒度更细的注解.

注解作用
@Getter自动添加getter方法
@Setter自动添加setter方法
@ToString自动添加toString方法
@EqualsAndHashCode自动添加equals和hashCode方法
@NoArgsConstructor自动添加无参构造方法
@AllArgsConstructor自动添加全属性构造方法,顺序按照属性的定义顺序
@NonNull属性不能为null
@RequiredArgsConstructor自动添加必需属性的构造方法,final+@NonNull的属性为必需

其中@Data = @Getter+@Setter+@ToString+@NoArgsConstructor+@RequiredArgsConstructor

下面来测试运行:
在这里插入图片描述

4. 图书管理系统

4.1 接口文档

  1. 需求;
    登录:用户输入账号和密码完成登录功能.
    列表展示:展示图书
  2. 接口定义
    登录接口
    [URL] POST /user/login [请求参数] name=admin&password=admin [响应] true //账号密码验证成功 false//账号密码验证失败 
    1. 图书列表展示
    [URL] POST /book/getList [请求参数] ⽆ [响应] 返回图书列表 [  {  "id": 1,  "bookName": "活着",  "author": "余华",  "count": 270,  "price": 20,  "publish": "北京⽂艺出版社",  "status": 1,  "statusCN": "可借阅"  },  ... 
    字段说明:
    id图书ID
    bookName图书名称
    author作者count 数量
    price定价
    publish图书出版社
    status图书状态 1-可借阅,2-不可借阅
    statusCN图书状态中文含义

4.2 前端代码

  • 登录页面
                  Document                       

登陆

用户名
密码
  • 图书列表
                  图书列表展示                                   

图书列表展示

选择 图书ID 书名 作者 数量 定价 出版社 状态 操作

    4.3 后端代码

    • 登录页面
    package com.jrj.library;  import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  @RequestMapping("/user") @RestController public class Login {     @RequestMapping("/login")     public Boolean login(String name, String password, HttpSession session){         if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){             return false;         }         if ("zhangsan".equals(name) && "123456".equals(password)){             session.setAttribute("userName",name);             return true;         }         return false;     } } 
    • 图书列表
      创建图书的属性
      package com.jrj.library;  import lombok.Data;  @Data public class BookInfo {//构造一本书所有的属性     public Integer id;     public String bookName;     public String author;     public Integer count;     public Integer price;     public String publish;     public Integer status;//1-可借阅,2-不可借阅     public String statusCN; }  
      返回图书列表:
      package com.jrj.library;  import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import java.util.ArrayList; import java.util.List; import java.util.Random;  @RequestMapping("/book") @RestController public class BookController {     @RequestMapping("/getList")     public List getList(){         List list = mockData();         for (BookInfo bookInfo:list){             if (bookInfo.status == 1){                 bookInfo.setStatusCN("可借阅");             }else{                 bookInfo.setStatusCN("不可借阅");             }         }         return list;     }     //模拟数据     private List mockData(){         List list2 = new ArrayList<>();         for (int i = 0; i < 5; i++) {             BookInfo bookInfo = new BookInfo();             bookInfo.setId(i);             bookInfo.setBookName("Java编程思想"+i);             bookInfo.setCount(1);             bookInfo.setPublish("机械工业出版社");             bookInfo.setPrice(new Random().nextInt(100));             bookInfo.setAuthor("高斯林");             bookInfo.setStatus(1);             list2.add(bookInfo);         }         return list2;     } }  

    测试运行:
    在这里插入图片描述
    登录页面正常
    在这里插入图片描述
    可正常登录,图书列表页面展示正确.

    5. 应用分层

    通过上面的几个案例,我们看到我们的代码平铺在我们的项目中,显得非常杂乱.所以我们要使用应用分层.
    在这里插入图片描述

    4.1 介绍

    常见的应用分层结构如下:
    在这里插入图片描述
    我们之前提到的"MVC",就是把整体的系统分成了Model(模型),View(视图)和Controller(控制器)三个层次.现在我们主流开发的方式是"前后端分离"的方式,后端开发不再需要关心前端的实现,所以对java后端开发者,又有了一种新的分层架构:把整体架构分为表现层、业务逻辑层和数据层.这种分层方式也称之为"三层架构".

    1. 表现层:就是展示数据结果和接受用户指令(接收参数和返回结果)的,是最靠近用户的⼀层;
    2. 业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现(拿到参数之后进行方法的具体实现);
    3. 数据层:负责存储和管理与应用程序相关的数据(比如数据库交互)

    4.2 具体在项目中的体现

    在我们创建Spring项目中,具体对分层的实现就是创建一个一个不同的目录,把代码分层管理起来.其中不同层面的目录一般用以下的命名方式:
    • Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
    • Service:业务逻辑层。处理具体的业务逻辑。
    • Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查.
    • Model: 用于存储对实物属性的描述
    下面我们对之前的图书管理的代码进行拆分重构:

    • 表现层
    package com.jrj.library.controller;  import com.jrj.library.service.LoginService; import jakarta.servlet.http.HttpSession; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  @RequestMapping("/user") @RestController public class LoginController {     @RequestMapping("/login")     public boolean login(String name, String password, HttpSession session){         LoginService loginService = new LoginService();         return loginService.login(name,password,session);     } } 
    package com.jrj.library.controller;  import com.jrj.library.BookInfo; import com.jrj.library.service.BookService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import java.util.ArrayList; import java.util.List;  @RequestMapping("/book") @RestController public class BookController {     BookService bookService = new BookService();     @RequestMapping("/getList")     public List getList(){         List bookInfos = new ArrayList<>();         bookInfos = bookService.getList();         return bookInfos;     } } 
    • 业务逻辑层
    package com.jrj.library.service;  import com.jrj.library.BookInfo; import com.jrj.library.dao.Data;  import java.util.List;  public class BookService {     public List getList(){         Data data = new Data();         List list = data.mockData();         for (BookInfo bookInfo:list){             if (bookInfo.status == 1){                 bookInfo.setStatusCN("可借阅");             }else{                 bookInfo.setStatusCN("不可借阅");             }         }         return list;     } } 
    package com.jrj.library.service;  import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils;  public class LoginService {     public Boolean login(String name, String password, HttpSession session){         if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){             return false;         }         if ("zhangsan".equals(name) && "123456".equals(password)){             session.setAttribute("userName",name);             return true;         }         return false;     } } 
    • 数据访问层
    import java.util.Random;  public class Data {     //向业务逻辑端提供数据     public List mockData(){         List list2 = new ArrayList<>();         for (int i = 0; i < 5; i++) {             BookInfo bookInfo = new BookInfo();             bookInfo.setId(i);             bookInfo.setBookName("Java编程思想"+i);             bookInfo.setCount(1);             bookInfo.setPublish("机械工业出版社");             bookInfo.setPrice(new Random().nextInt(100));             bookInfo.setAuthor("高斯林");             bookInfo.setStatus(1);             list2.add(bookInfo);         }         return list2;     } }  
    • 实物描述
    package com.jrj.library.model;  import lombok.Data;  @Data public class BookInfo {//构造一本书所有的属性     public Integer id;     public String bookName;     public String author;     public Integer count;     public Integer price;     public String publish;     public Integer status;//1-可借阅,2-不可借阅     public String statusCN; }  

    上面的"三层架构",遵循了一种软件设计的原则,叫做"高内聚,低耦合".
    高内聚指的是⼀个模块中各个元素之间的联系比较紧密.如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即"高内聚".
    低耦合指的是软件中各个层、模块之间的依赖关联程序越低越好。修改⼀处代码,其他模块的代码改动越少越好.
    在这里插入图片描述

    前面提到的MVC架构模式和三层架构模式有什么区别?
    MVC架构模式由三部分组成,分别是:模型(Model),视图(View)和控制器(Controller).
    三层架构将业务应用划分为:表现层,业务逻辑层,数据访问层.
    MVC模式强调数据和视图分离,将数据展示和数据处理分开,通过控制器对两者进行组合
    三层架构强调不同维度数据处理的高内聚和低耦合,将交互界面,业务处理和数据库操作的逻辑分开.
    在这里插入图片描述

    相关内容

    热门资讯

    专业讨论!德扑之星真破解套路(... 专业讨论!德扑之星真破解套路(辅助挂)软件透明挂(有挂了解)-哔哩哔哩;人气非常高,ai更新快且高清...
    每日必看!智星德州菠萝外挂检测... 每日必看!智星德州菠萝外挂检测(辅助挂)软件透明挂(有挂教学)-哔哩哔哩1、玩家可以在智星德州菠萝外...
    透视透明挂!轰趴十三水有后台(... 轰趴十三水有后台赢率提升策略‌;透视透明挂!轰趴十三水有后台(辅助挂)软件透明挂(有挂详情)-哔哩哔...
    发现玩家!德扑ai助手软件(辅... 发现玩家!德扑ai助手软件(辅助挂)透视辅助(有挂教学)-哔哩哔哩;玩家在德扑ai助手软件中需先进行...
    一分钟了解!x-poker辅助... 一分钟了解!x-poker辅助软件(辅助挂)辅助透视(有挂攻略)-哔哩哔哩1、每一步都需要思考,不同...
    一分钟揭秘!德州最新辅助器(辅... 一分钟揭秘!德州最新辅助器(辅助挂)透视辅助(有挂攻略)-哔哩哔哩;德州最新辅助器最新版本免费下载安...
    玩家攻略推荐!德州辅助(辅助挂... 玩家攻略推荐!德州辅助(辅助挂)辅助透视(有挂了解)-哔哩哔哩是由北京得德州辅助黑科技有限公司精心研...
    揭秘真相!pokernow德州... 《揭秘真相!pokernow德州(辅助挂)辅助透视(有挂介绍)-哔哩哔哩》 pokernow德州软件...
    五分钟了解!德州之星辅助器(辅... 五分钟了解!德州之星辅助器(辅助挂)辅助透视(有挂透明)-哔哩哔哩1、很好的工具软件,可以解锁游戏的...
    推荐一款!pokermaste... 1、推荐一款!pokermaster有外挂(辅助挂)透视辅助(有挂教学)-哔哩哔哩;详细教程。2、p...