SpringMVC

SpringMVC

一。概念:

Spring Web MVC是一个Web框架,简称为SpringMVC

MVC定义:

MVC就是把一个项目分成三部分

MVC是一种思想,Spring进行实现,因此称为SpringMVC

SpringBoot是创建SpringMVC项目

当前时期MVC已经发生了变化,后端人员不涉及前端页面的开发,所以就没有了view层

所以View层有一种解释,之前返回的是视图,现在返回的是视图所需要的数据

java 复制代码
@RequestMapping("/hhh")
public String sayHi(){
    return "hehe";
}

这里的return返回的hehe就是返回的就是视图所需的数据

二。SpringMVC:

1。建立连接(客户端和服务器)

@RequestMapping. 路由映射,这个标签可以修饰方法,也可以修饰类

访问地址:类的路径+方法路径

java 复制代码
@ResponseMapping("/hhh")
@RestController
public class HelloController{
  @RequestMapping("/sayHi")
  public String sayHi(){
    return "Hi";
  }
  @RequestMapping("sayHello")
  public String sayHello(){
    return "hello";
  }
}

如果想访问sayHello这个方法,只需运行然后在浏览器地址栏中输入127.0.0.1:8080/hhh/sayHello

@RequestMapping支持GET和POST请求(其实支持所有类型的请求)

java 复制代码
@RequestMapping("/sayHello")
public String sayHello(){
  return "hello";
}
//注解中没有写属性名,那么默认为value
@RequestMapping(value="/sayHello",method=RequestMethod.GET)
public String sayHi(){
  return "Hi";
}
//注解中写method可以限制请求方式,向上面这种就是限制了只能使用GET方法

注:如果出现404原因可能是url写错了,如果出现405原因可能是使用的请求出现问

2。请求

主要就学习如何传参(发送命令)

(1)传递单个参数:
java 复制代码
@RequestMapping("/m1")
public String m1(String name){
  return "收到的name为:"+name;
}

这里的name不考虑是怎么得到的,怎么把数据给后端是前端要考虑的事情

要注意一点请求中的参数名要和后端的参数名一样,例如PostMan发送请求

(2)传递多个参数
java 复制代码
@RequestMapping("/m2")
public String m2(String name,int age){
  return "收到的参数name:"+name+",age:"+age;
}

如果使用基本类型,必须传值,不传会报错

因此如果后期在这个方法中想加入一些新的参数,或者删除一些参数,就要通知调用方(前端...)把参数传过来,这样就会很麻烦,为力解决这个问题,就要把参数进行封装,使用对象

(3)传递对象
java 复制代码
@RequestMapping("/m4")
public String m4(Person person){
  return "接收到的参数Person:"+person.toString();
}
java 复制代码
public class Person{
  Integer id;
  String name;
  Integer age;
  //让IDEA生成一下getter和setter和toSting
}

把传入的对象封装成对象之后,代码就会变的很灵活,如果发送方(前端)没有给某个参数传值,我们可以在对象(Person)中加入一些默认值之类的逻辑,这样就算前端没有传值,代码也不会报错,可以正常运行,因此,开发中接口的参数常常 定义为对象

(4)后端参数重命名

如果前端传来的名字不合适,后端是可以对名字进行重命名的

java 复制代码
@RequestMapping("/m5")
public String m5(@RequestParam("name") String username){
  return "收到的参数name:"+username;
}

@RequestParam标签里的内容就是前端传来的参数名,后面的是后端想改成的名字

还有就是@RequestParam标签里的内容是必传参数,如果不传就会报错,在这个标签中也可将其设置为非必传标签

java 复制代码
@RequestMapping("/m5")
public String m5(@RequestParam(value+"name",required=false) String username){
  return "收到的参数name:"+username;
}
(5)传递数组

当我们请求中,同一个参数有多个值的时候,浏览器会我们给封装成一个数组

http://127.0.0.1:8080/hhh/m6?arrayName=zhangsan,lisi,wangwu
http://127.0.0.1:8080/hhh/m6?arrayName=zhangsan&arrayName=lisi&arrayName=lisi
java 复制代码
@RequestMapping("/m6")
public String m6(String[] arrayName){
  return "返回的参数arrayName:"+Array.toString(arrayName);
}

注:1.后端无需考虑数据是怎么传过来的,就像厨师一样,不用管用户是线上还是线下点餐,只要把菜做好就行

2.发送GET请求默认是从url的queryString中获取,如果用PostMan的Body中的x-www-...来发送GET请求,可能会导致后端拿不到参数

(6)传递集合
java 复制代码
@RequestMapping("/m7")
public String m7(@RequestParam List<String> listParam){
  return "接收到的参数listParam:"+listParam;
}

补充:状态码:

(1)HTTP状态码:不是后端自定义的:2xx:成功,3xx:重定向,4xx:客户端错误,5xx:服务端错误

(2)业务状态码:http响应成功的前提下,业务的响应结果分为不同的状态,例如用户登陆:密码正确200,错误-1

(7)传递JSON

正常来说,开发中上面的六种方法都不常用,最常用的就是json格式进行传递

json本质上是一个字符串,表示对象的字符串

以下几种JSON形式都是正确的

json 复制代码
{"name"="zhangsan","age"=10}
[{"name"="zhangsan","age"=10},{"name"="lisi","age"=19}]

传递Json数据,需要使用@RequestBody

java 复制代码
@RequestMapping("/m8")
public String m8(@RequestBody Person person){
  return "接收的数据person:"+person.toString();
}

不加这个@RequestBody注解的话,person就只能从url的queryString中拿,如说Body中写json就无法被传递

(8)获取文件,图片
java 复制代码
@RequestMapping("/m9")
public String m9(@RequestPart MultipartFile file){
  System.out.println(file.getOriginalFilename());
  return "success";
}

用postMan发送请求的时候,要选中from-data选项,并且Key中的元素要和传入的元素的参数名相同

java 复制代码
@RequestMapping("/m9")
public String m9(@RequestPart MultipartFile file){
  System.out.println(file.getOriginalFilename());
  file.transferTo(new File("D:/temp/"+file.getOriginalFilename()));
  return "success";
}

加上file.transferTo(new File("D;/temp/"+file.getOriginalFilename()));这句话就可以把文件存入到自己电脑的某个地方

(9)cookie和session

Http是无记忆功能,现在请求和过一会儿请求,同样的参数得到的结果是一致的(处理逻辑一致)

cookie:客户端 session:服务器端

举个例子来理解cookie和session:假设我去医院,要先挂号,这时医生会给我一个就诊卡,这个就诊卡就相当于cookie,就诊卡中存储的是用户的信息(身份标识),我要拿着就诊卡去各个科室,见到医生之后,医生会让我刷就诊卡,书卡这个过程,就会通过医院系统,查询我的身份标识,进一步得到完整的身份信息,显示在医生的电脑上。这里的完整的身份信息比如诊断信息,用户详细信息,以往病例...,每个用户都有一份这样的信息,这些数据在服务器上怎么组织的呢?当然是存储在数据库之中的,在服务器代码逻辑展开执行的过程中,这些数据就会被从数据库查询出来,先临时保存到某个内存结构,后续有什么修改之类的,只用修改内存,重新写入就行;这里的内存结构其实就是session

获取cookie:

法一:使用Spring内置对象(HttpServletRequest和HttpServletResponse)

java 复制代码
@RequestMapping("hhh")
public String getCookie(HttpServletRequest request,HttpServletResponse response){
  Cookie[] cookies=request.getCookies();
  for(int i=0;i<cookies.length;i++){
    System.out.pringln(cookie.getName()+":"+cookie.getValue());
  }
  return "获取cookie成功";
}

法二:使用@CookieValue标签

java 复制代码
@RequestMapping("hh")
public String getCookie2(@CookieValue String bite){
  return "cookie存储的值bite:"+bite;
}

使用标签的方法有一个坏处就是它只能一个一个cookie去拿,无法向法一一样,一次把所有cookie值拿到,通过循环去获取值,当然也可以使用一次获取多个cookie的方式,只是要多写几次cookieValue注解

java 复制代码
@RequestMapping("hh")
public String getCookie2(@CookieValue String bite,@CookieValue String name,@CookieValue int age){
  return "cookie存储的值bite:"+bite;
}

获取session:

法一:

java 复制代码
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request){
  HttpSession session=request.getSession();
  session.setAttribute("username","zhangsan");
  return "success";
}


@RequestMapping("/getSession")
public String getSession(HttpServletRequest request){
  HttpSession session=request.getSession(false);
  if(session!=null){
    String username=(String)session.getAttribute("username");
    return "用户登陆"+username;
  }
  return "sesseion为空";
}

这个写法和Servlet几乎是一样的

法二:

java 复制代码
@RequestMapping("hhh")
public String getSession1(@SessionAttribute String username){
  return "username"+username;
}

使用这种注解的方法可以迅速的从session中获取到想要的参数

法三:

java 复制代码
@RequestMapping("hhihih")
public String getSession3(HttpSession session){
  String username=(String)session.getAttribute("username");
}

getSession3方法中的参数HttpSession session就等价于HttpSession session=request.getSession(true);

3。响应

(1)返回静态页面:

在resource文件夹下有一个static文件夹,在这个文件夹放入要写的前端代码

java 复制代码
@Controller
public class ReturnController{
  @RequestMapping("/index")
  public String returnIndex(){
    return "/index.html";//请求到static文件夹中找到这个文件
  }
}

Controller的作用就是告诉Spring帮我们管理代码,@controller返回的是视图,随着前后端端分离,后端不在处理页面,只返回页面所需的数据,因此经常使用@ResponseBody,而@RestController是两者的结合体

(2)返回Json

当我们的接口返回的是String,Int,double...时,content-type时text/html

当我们接口返回的是对象,map的时候,content-type自动设置为application/json

三。综合性练习:

1.加法计算器:

前端代码:

html 复制代码

后端代码:

java 复制代码
@RequestMapping("/hhh")
@RestController
public class calcController{
  @RequestMapping("/sum")
  public String sum(Integer num1,Integer num2){
    int sum=num1+num2;
    return "计算结果为:"+sum;
  }
}
2.登陆案例:

(1)登陆接口:/user/login

userName=?&password=?

接口返回:true密码正确,false密码错误

(2)获取用户的登陆信息:/user/getUserInfo

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

java 复制代码
@RequestMapping("/user")
@RestController
public class UserController{
  @RequestMapping("/login")
  public Boolean login(String username,String password,HttpSession session){
    //step1:先判断传进来的username和password是否合法
    if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)){
      return false;
    }
    //step2:进行账号和密码的校验
    if("zhangsan".equals(username)&&"edg".equals(password)){
      session.setAttribute("username","zhangsan");
      return true;
    }
    return false;
  }
  
  @RequestMapping("/getUserInfo")
  public String getUserInfo(HttpServletRequest request){
    HttpSession session=request.getSession("false");
    String username=null;
    if(session!=null){
      userName=(String)session.getAttribute("username");
    }
    return userName;
  }
}
3.留言板案例:

前端没有保存数据的能力,后端要把数据保存下来,由于目前还还没学如何和数据库建立连接,所以就使用回文的方式,将数据放到内存中

接口定义:

提交留言:/message/publish ,参数:MessageInfo(from,to,message),返回结果:true/false

查看所有留言:/message/getMessageList,参数:无,返回结果:List

前端:

复制代码

后端:

java 复制代码
public class MessageInfo{
  private String from;
  private String To;
  private String message;
  //用IDEA生成以下setter和getter和toString
}
java 复制代码
@RequestMapping("/message")
@RestController
public class MessageController{
  private List<MessageInfo> messageinfos=new ArrayList<>();
  @RequestMapping("/publish")
  public Boolean publishMessage(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
  }
}
4.图书管理系统:

现在就只完成图书管理系统的两个功能,登陆(用户输入账号,密码完成登陆)和列表(展示图书),剩下的功能以后回专门写一篇博客

定义前后端交互的接口:

1.登陆:

URL:/user/login。 参数:userName=?&password=? 响应:true/false

2.图书列表展示:

URL:/book/getBookList。 参数:无。 响应:List

后端:

(1)BookInfo文件:

java 复制代码
@Data
public class BookInfo{
  private Integer id;
  private String bookName;
  private String author;
  private Integer count;
  private BigDecimal price;//这个类型是专门用来对价格进行修饰的
  private String publish;
  private Interger status;//1-可借  2-不可借
  private String statusCN;
}

(2)UserController文件:

java 复制代码
@RequestMapping("user")
public class UserController{
  @RequestMapping("login")
  public Boolean login(String username,String password,HttpSession session){
    if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)){
      return false;
    }
    if("zhangsan".equals(username)&&"edg".equals(password)){
      session.setAtrribute("username",username);
      return true;
    }
    return false;
  }
}

(3)BookController文件:

一共有三步:获取图书数据->对图书数据进行处理->返回数据

由于目前还没学连接数据库,那么就要造一些假数据,来协助后端完成代码

java 复制代码
@RestController
public class BookController{
  @RequestMapping("/getBookList")
  List<BookInfo> bookInfos=mockData();//mock表示虚拟的意思,假数据
  for(int i=0;i<bookInfos.length();i++){
    if(bookInfos.get(i).getStatus()==1){
      bookInfo.setStatusCN("可借");
    }else{
      bookInfo.setStatusCN("不可借");
    }
  }
}

private List<BookInfo> mockData(){
  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(100));
    bookInfo.setPrive(new BigDecimal(new Random().nextInt(100)));
    bookInfo.setPublish("出版社"+i);
    bookInfo.setStatus(i%5==0?2:1);
    bookInfos.add(bookInfo)l;
  }
  return bookInfos;
}
相关推荐
天天扭码4 分钟前
五天SpringCloud计划——DAY1之mybatis-plus的使用
java·spring cloud·mybatis
程序猿小柒9 分钟前
leetcode hot100【LeetCode 4.寻找两个正序数组的中位数】java实现
java·算法·leetcode
不爱学习的YY酱1 小时前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
丁总学Java1 小时前
Maven项目打包,com.sun.tools.javac.processing
java·maven
kikyo哎哟喂1 小时前
Java 代理模式详解
java·开发语言·代理模式
Doker 多克1 小时前
Spring AI 框架使用的核心概念
人工智能·spring·chatgpt
duration~1 小时前
SpringAOP模拟实现
java·开发语言
小码ssim1 小时前
IDEA使用tips(LTS✍)
java·ide·intellij-idea
潜洋2 小时前
Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序
java·spring boot·后端
暮志未晚Webgl2 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5