Java SpringMVC(二) --- 响应,综合性练习 - 指南

SpringMVC

响应

返回静态页面

  1. 返回静态页面
    1.元注解:可以被其他注解使用的叫做元注解
    @Target:表示注解修饰的对象
    {ElementType.TYPE}表示可以修饰类和接口
    @Documnted:文档,比如jdk有很多的注释,表示要不要保留这些注释

2.@RestController包括:@Controller和@ResponseBody
现在@RestController被用来返回数据了
在这里插入图片描述

3.@Controller的作用:告诉Spring,帮我们管理这个代码,我们后续访问时,才能访问到,才能使用我们写的代码,不写这个注解,Spring是不管这个代码的
在这里插入图片描述
注解的生命周期:
在这里插入图片描述
举个例子,写一个简单的静态页面(会打印index.html文件上的内容):
在这里插入图片描述
如果有多个注解,注解的顺序是不影响结果的

@RequestMapping("/return")
//@RestController // 返回数据
@Controller // 返回视图
public class ReturnController {
@RequestMapping("/index")
public String returnIndex(){
// 使用@RestController时返回数据
// 这时是返回这个数据,不是返回这个页面
return "/index.html";
}
}

返回数据@Responsebody

  1. @Responsebody可以修饰类,也可以修饰方法,修饰类的时候,表示这个类下的所有方法,返回的均为数据
    修饰方法时,表示该方法返回的是数据
  2. 如果一个类中的所有方法返回的都是数据,我们可以把这个注解加在类上

返回一个数据

@ResponseBody
@RequestMapping("/returnData")
public String returnData(){
return "返回的是一个数据";
}

返回html的代码片段

  1. 返回html的代码片段
// 返回代码片段
@ResponseBody
@RequestMapping("/returnHtml")
public String returnHtml(){
return "<h1>这是一个代码</h1>";
}

在这里插入图片描述
在这里插入图片描述

返回一个JSON

  1. 返回一个JSON
// 返回的是一个json对象
@ResponseBody
@RequestMapping("/returnJson")
public Person returnJson(){
Person person = new Person();
person.setId(1);
person.setAge(5);
person.setName("zhangsan");
return person;
}

在这里插入图片描述
2. 返回一个Map对象

// 返回的是一个json对象
@ResponseBody
@RequestMapping("/returnJson")
public Person returnJson(){
Person person = new Person();
person.setId(1);
person.setAge(5);
person.setName("zhangsan");
return person;
}
@ResponseBody
@RequestMapping("/returnMap")
public Map<String,String> returnMap(){
  Map<String,String> map = new HashMap<>();
    map.put("k1","v1");
    map.put("k2","v2");
    map.put("k3","v3");
    return map;
    }

返回一个对象时,会自动帮我们设置为json格式,所以说返回的类型会被自动设置

设置状态码

  1. 状态码不影响页面的展示(显示的还是代码返回的内容,只是使用fiddler抓包时看到响应是401)
@ResponseBody
@RequestMapping("/returnStaus")
public String returnStaus(HttpServletResponse response){
// 401通常表示没有登录
response.setStatus(401);
return "设置状态码";
}

在这里插入图片描述

设置Header

  1. RequestMapping
    method用来设置(限制)请求的方式
    在这里插入图片描述
    下面这些方式通常都不会使用,限制的太多了
    在这里插入图片描述

  2. 使用produces来设置Header返回的类型

// 通过produces改变返回类型
@ResponseBody
@RequestMapping(value = "/r1",produces = "application/json; charset=utf-8")
public String r1(HttpServletResponse response){
// 可以设置header
// header是键值对形式的
response.setHeader("myhead","myhead");
return "{'OK',1}";
}

在这里插入图片描述
在这里插入图片描述

总结

  1. 对上面内容的总结:
    在这里插入图片描述

综合性练习

  1. 练习前端和后端的交互过程,请求,响应的处理

1. 加法计算器

  1. 前端代码(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>
  1. 后端代码:
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){
// 这就是打印日志
System.out.println("--------------------sum");
Integer sum = num1 + num2;
return "计算的结果为: " + sum;
}
}

3. 如果报错了,该如何定位错误位置:
1.先定位前端还是后端问题
通过日志
(1) 前端:F12 看控制台
(2) 后端:接口,控制台日志

检测请求是否到达后端的方法:
(1) 可以进行抓包,看请求的路径

(2) 可以在后端进行打印信息,如果请求到了就会打印信息,否则不会打印信息(打印日志)

(3) 后端可以通过url或者是postman进行接口的测试(测试接口)

测试接口:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 用户登陆

  1. 用户登录时,前端存在缓存问题,还是显示之前的页面信息,那么我们该如何清理缓存?

显示的不是登录后,用户的信息,而是显示之前这个html中的信息
在这里插入图片描述
可以点击maven中的clean清除里面的缓存,直接运行代码里面就包含了打包的工作,浏览器中也是存在缓存的,可能还需要清理浏览器中的缓存(清除浏览器的记录就可以了)

  1. 写代码之前做的工作:
    在这里插入图片描述

  2. 为什么登录时要设置Session的信息?
    在这里插入图片描述

  3. 可以先测试后端的接口(后端的接口和前端的代码是没有关系的),然后再写前端的代码

  4. 前端的代码:

登录的逻辑:

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() {
                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>

登录成功后,进行页面跳转,显示用户名信息:

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:"get",
            success:function(username){
            $("#loginUser").text(username);
            }
            });
          </script>
        </body>
      </html>
  1. 后端的代码:
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){
// 1. 检验输入的用户名和密码是合法的(校验参数的合法性)
//        if(usename == null || usename.length() == 0 || password == null ||
//        password.length() == 0){
//            return false;
//        }
// Spring也提供了一种方式检验用户名和密码是否和法的
// StringUtils.hasLength()检验字符串是否有长度
if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){
return false;
}
// 2. 进行用户名和密码的校验
if("admin".equals(userName) && "admin".equals(password)){
// 设置Session,存储用户这次登录的信息
session.setAttribute("usename","admin");
return true;
}
return false;
}
// 第一种写法:
// 如果登录成功,返回登录的用户的信息
//    @RequestMapping("getUserInfo")
//    // HttpSession session 没有session,会自动创建一个session
//    public String getUserInfo(HttpSession session){
//        // 从Session中获取用户的登录名
//        String usename = (String)session.getAttribute("usename");
//
//        return usename;
//    }
// 第二种写法:
@RequestMapping("/getUserInfo")
public String getUserInfo(HttpServletRequest request){
// 从Session中获取用户的登录名
// 没有Session,就不要创建一个Session
HttpSession session = request.getSession(false);
String usename = null;
if(session != null) {
usename = (String) session.getAttribute("usename");
}
return usename;
}
}

展示效果:
在这里插入图片描述
登录后进行跳转页面:
在这里插入图片描述

项目如何debug

  1. 先打一个断点
  2. 然后点击这个小虫子,进行启动代码

断点打成功,会有一个√号
在这里插入图片描述

在这里插入图片描述
3. 后面步骤的调试项目和我们平常调试代码是一样的

3. 留言板

  1. 前端没有保存数据的功能,后端把数据保存下来(保存在内存,数据库,文件中等等…)
    为了让留言板刷新内容不会消失
    在这里插入图片描述
  2. 接口定义
    (1) 提交留言(给服务器)
    /message/publish
    参数:MessageInfo(from,to,message)
    返回结果:true/false

(2) 查看所有留言(后端显示所有留言)
/message/getMessageList
参数:无
返回结果:List< MessageInfo >

  1. lombok:工具包
    (1) 作用:如果一个类中有许多的变量,都需要get和set方法来设置,那就会很麻烦,这时使用lombok,就可以不用写这些get和set方法了

(2) 对于不熟悉的包,如何选择maven版本,建议选择次新版本(使用频率比较高的版本)

在这里插入图片描述
(3) @Data这个注解帮我们写了get方法和set方法,这个工具可以针对所有属性写get和set方法,也可以单独对某个属性写get和set方法
在这里插入图片描述
单独对某个属性写get和set方法
在这里插入图片描述
SpringBoot帮我们管理了这些包,所以应该集成了这些包,安装一个插件就可以使用插件导入这个包了,就不需要从Maven仓库中导入这个包了

在这里插入图片描述
在这里插入图片描述

lombok

  1. lombok中的一些注解
    在这里插入图片描述
    在这里插入图片描述

  2. @ToString:自动帮我们写了ToString方法
    在这里插入图片描述

留言板

  1. 为什么前端校验之后,后端还需要校验?
    可能不是通过前端页面发起的请求,可能是一个非法的请求,这是最重要的原因

在这里插入图片描述
VSCode格式化:alt + shift + F,进行代码的对齐

  1. 前端代码:

messagewall.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) {
              //2. 拼接节点的 html
            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. 拼接节点的 html
            var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
              //3. 把节点添加到页面上 
              $(".container").append(divE);
              //4. 清空输入框的值
              $('#from').val("");
              $('#to').val("");
              $('#say').val("");
              } else {
              //添加失败
              alert("留言发布失败");
              }
              }
              });
              }
            </script>
          </body>
        </html>
  1. 后端代码:

MessageController:

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 java.util.ArrayList;
import java.util.List;
@RequestMapping("/message")
@RestController
public class MessageController {
private List<MessageInfo> messageInfos = new ArrayList<>();
  // 1. 提交留言
  @RequestMapping("/publish")
  public Boolean publishMessage(MessageInfo messageInfo){
  // 1. 进行参数的校验
  //    hasLength表示没有为空
  if(!StringUtils.hasLength(messageInfo.getFrom()) ||
  !StringUtils.hasLength(messageInfo.getTo())||
  !StringUtils.hasLength(messageInfo.getMessage())){
  // 只要一个为空,就不发送
  return false;
  }
  // 2.添加留言
  messageInfos.add(messageInfo);
  return true;
  }
  // 2. 查看留言
  @RequestMapping("/getMessageInfo")
  public List<MessageInfo> getMessageInfo(){
    return messageInfos;
    }
    }

用到的类:
MessageInfo:

package com.example.demo.controller;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Date;
@Data
class MessageInfo {
private String from;
private String to;
private String message;
// private Date CreateTime;
}

效果展示:
在这里插入图片描述

4. 图书管理系统

  1. 目标(这里不是完全体的需求,后面会继续完善的):
    在这里插入图片描述

  2. 定义前后端交互接口
    (1) 登录
    url:/user/login
    参数:useName = ? & password = ?
    响应:true / false

(2) 图书列表展示
url:/book/getBookList
参数:无
响应:List< BookInfo >

  1. 后端代码:

图书类:BookInfo

package com.example.book2;
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;// 图书的中文状态说明
}

登录:
UserController:

package com.example.book2;
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 useName, String password, HttpSession session){
// 1. 校验参数
// useName和password只要一个为空就返回false
if(!StringUtils.hasLength(useName) || !StringUtils.hasLength(password)){
return false;
}
/*
useName.equasl("admin"),如果useName为空时,会报空指针异常
这是一个开发习惯
*/
// 2. 验证账号,密码是否正确
if("admin".equals(useName) && "admin".equals(password)){
// 账号密码正确
// 存储Session,把用户名存起来
session.setAttribute("useName",useName);
return true;
}
return false;
}
}

图书列表展示:

BookController:

package com.example.book2;
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);
        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;
        }
        }

展示效果:
在这里插入图片描述
在这里插入图片描述

应用分层

  1. 三层架构
    dao/db 通常指的是数据访问层中与数据库直接相关的组件
    db中就是数据库相关的操作
    在这里插入图片描述
  2. 代码中数据分层的表现:
    在这里插入图片描述
  3. 那么这些代码的包也可以进行分层
    model存的是数据对象(实体类)
    在这里插入图片描述
posted @ 2025-11-06 14:24  yangykaifa  阅读(6)  评论(0)    收藏  举报