【SpringMVC】和客户端连接,接收参数,返回数据基础教程

前言

前面我们介绍的都是关于SprintBoot的基础知识,涉及到的知识也都是关于Spring的Core项目,还没有和网络的请求建立连接并交互

MVC

但是我们先来看一下MVC是什么,MVC就是描述了我们和客户端如何交互的思想。也就是我们说的MVC三层结构
【SpringMVC】和客户端连接,接收参数,返回数据基础教程_第1张图片

  1. 用户的输入最先到的地方就是控制器
  2. 控制器接收到请求之后就向数据库中读取数据
  3. 控制器的操作接收到来自数据库中的数据之后就将内容展示到View中
  4. 用户最后读取View信息

SpringMVC

我们上面明白了MVC,但是SpringMVC是什么呢?

  1. MVC是一种设计模式,SpringMVC是一个具体的实现
  2. SpringMVC也是基于Servlet的API完成的,进行了封装
  3. SpringMVC是Spring的一个Web项目.可以完成数据交流

其实,SpringMVC是Spring的web项目中的一个,并且Spring和SpringMVC的年龄都是比SpringBoot的年龄要大的

使用SpringMVC

也就是使用Spring创建项目的时候,我们要勾选Spring Web 表明这是一个web项目

【SpringMVC】和客户端连接,接收参数,返回数据基础教程_第2张图片

主要经过一下的步骤:

  1. 程序和客户的连接. 也就是用户通过浏览器的地址可以和java程序连接起来
  2. 获取客户端的参数. 客户端向程序发送过来的请求可能会带有参数,所以服务器要带来参数
  3. 返回数据 根据请求处理之后的响应数据要返回给客户端

程序和客户连接

使用@RequestMapping

@RequestMapping是一个路由选择,里面的参数是用户访问的网址

直接修饰方法

如果@RequestMapping直接修饰在方法上面,那么它的参数就是用户直接访问的参数

@ResponseBody  
@org.springframework.stereotype.Controller  
public class Controller {  
	//直接写在方法上面
	@RequestMapping("/printMVC")  
    public String print(){  
        return "hello,SpringMVC";  
    }  
}

上面的代码中,@RequestMapping("/printMVC") 直接修饰了方法,所以我们访问的时候,直接http://localhost:8080/printMVC 即可

修饰方法和类

@RequestMapping还可以同时修饰类和方法

这个时候,如果我们要访问一个方法的话,访问的网址应当是类网址/方法网址

package com.example.demo.controller;  
  
  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.ResponseBody;  
  
@RequestMapping("/test")  
@ResponseBody  
@org.springframework.stereotype.Controller  
public class Controller {  
    @RequestMapping("/printMVC")  
    public String print(){  
        return "hello,SpringMVC";  
    }  
  
    @RequestMapping("/printHello")  
    public String print2(){  
        return "hello,Hello";  
    }  
  
}

如果我们要打印hello,SpringMVC 就访问http://localhost:8080/test/printMVC

如果我们要打印hello,hello 就访问http://localhost:8080/test/printhello

相当于是多加了一层目录结构

GET和POST请求

@RequestMapping 可以支持GET请求和POST请求

get请求:

GET http://localhost:8080/test/printMVC HTTP/1.1
Host: localhost:8080

post请求:

POST http://localhost:8080/test/printMVC HTTP/1.1
User-Agent: PostmanRuntime/7.29.0

默认情况下Get请求和Post请求都是可以的

设置请求参数method

我们可以访问某一个方法的时候,只能接收一种类型的请求

通过指定method,指定RequestMehtod的POST请求,那么这个方法就只可以接收POST请求

@RequestMapping(value = "/printHello",method = RequestMethod.POST)

RequestMethod类的请求有以下这些:

GET,  
HEAD,  
POST,  
PUT,  
PATCH,  
DELETE,  
OPTIONS,  
TRACE;

但是常用的只有GET和POST

@PostMapping

只可以接收Post请求

@PostMapping("/printMVC")  
public String print(){  
    return "hello,SpringMVC";  
}
@GetMapping

只可以接收Get请求

@GetMapping("/printHello")  
public String print2(){  
    return "hello,Hello";  
}

获取参数

传递单个参数

直接使用方法的参数就可以接收到传递的参数了

@RequestMapping("/onePara")  
public String getOnePara(String name){  
    return name+" 你好";  
}

访问的时候:

http://localhost:8080/para/onePara?name=java

访问的参数名要和方法的参数名相同

另外,传递数字的时候,接收的参数最好还是使用包装类,因为如果是int类型的话,如果没有接收到参数,就直接报错.
但是如果是Integer类型,没有接收到参数,id的值就是null
不会再参数接收的时候就报错

@RequestMapping("/object")//参数的接收都应该是包装类  
public People getObject(Integer id){  
    People people=new People();  
    people.setId(id==null?0:id);  
    people.setName("cx");  
    people.setPassword("1234");  
    return people;  
}

重命名参数

如果前端的Key和后端的key不一样是不可以的,为了解决这个问题,我们就可以重命名参数

如前端传递的name.经过重命名之后,后端可以为newName

使用**@RequestParam(“前端的名字”)在方法的参数前面标记**

@RequestMapping("/para")  
@Controller  
@ResponseBody  
public class ControllerPara {  
    @RequestMapping("/onePara")  
    public String getOnePara(@RequestParam("name") String newName){  
        return newName+" 你好";  
    }  
}

非必传参数设置

如果我们使用了@RequestParam注解的话,所以如果前端没有传递参数的话就会报错,
但是如果不加@RequestParam的话,就不会报错,原因是

下面RequestParam类的实现:

public @interface RequestParam {  
    @AliasFor("name")  
    String value() default "";  
  
    @AliasFor("value")  
    String name() default "";  
	
	//这里的required默认是true的,表示一定要写上
    boolean required() default true;  
  
    String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";  
}

所以我们就可以让RequestParam的required里面改为false.这样的话我们就算缺省也可以

@RequestMapping("/para")  
@Controller  
@ResponseBody  
public class ControllerPara {  
    @RequestMapping("/onePara")  
    public String getOnePara(@RequestParam(value = "name",required = false) String newName){  
        return newName+" 你好";  
    }  
}

传递多个参数

方法里面有多个参数,其中前端在传递参数的时候,不用考虑参数的位置问题,而是根据前端的名字和后端进行匹配

@RequestMapping("/para")  
@Controller  
@ResponseBody  
public class ControllerPara {  
    @RequestMapping("/onePara")  
    public String getOnePara(@RequestParam(value = "name",required = false) String newName,  
                             @RequestParam(value = "password",required = false) String newPassword){  
        return newName+" 你好 "+"密码是 "+newPassword;  
    }  
}
localhost:8080/para/onePara?password=1111&name=lisi

传递对象

如果要传递的参数过多,我们就可以将参数都放到一个类里面,这样就比较方便了

@RequestMapping("/getbyobject")  
public People getByBoject(People people){return people;}

如果没有传递参数:

localhost:8080/para/getbyobject

{
    "id": 0,
    "name": null,
    "password": null
}

传递参数了:

同样,我们传递对象的参数的时候也是使用的键值对进行匹配到类的属性中


请求url:
localhost:8080/para/getbyobject?id=1&name=lllll&password=1234

返回结果值:
{
    "id": 1,
    "name": "lllll",
    "password": "1234"
}

使用JSON传递数据

如果我们使用JSON传递对象的话,因为默认它是一个对象,所以我们接收的时候,在方法的参数前面加上@RequestBody

@RequestMapping("/getbyobject")  
													//加上RequestBody就可以使用JSON传递了
public People getByBoject(@RequestBody People people){return people;}

通过URL获取属性

有一种另类的URL的写法,就是文件路径部分正常写,但是参数部分只写参数的value部分,value之间使用/隔开

这个就是从URL中获取属性,前面是属于从URL的参数部分获取属性

  1. 在RequestMapping的路径里面要指定要传递的参数的名字
  2. 在方法的参数部分要和上面的一致,前面也要加上@PathVariable注解
@RequestMapping("/getbyurl/{name}/{password}")  
public String getByURL(@PathVariable String name,@PathVariable String password){  
    return "name: "+name+" password: "+password;  
}

前端的URL:

http://localhost:8080/para/getbyurl/cx/123

上传文件

  1. 方法的参数要接收图片的话,图片要是MutipartFile
  2. MutipartFile的前面也要加上@RequestPart注解
public boolean upFile(Integer id , @RequestPart("img")MultipartFile file){  
    boolean result=false;  
    try {  
        file.transferTo(new File("D:/桌面/hhh.png"));  
        result=true;  
    } catch (IOException e) {  
        log.error(e.getMessage());  
    }  
    return result;  
}

但是我们最好是指定好文件的目录和名字,要不然就会发生文件的覆盖的情况.

1. 设置目录位置

我们可以根据环境的不同设置不同的目录,对于开发环境和生产环境指定不同的路径

# 生产环境  
img:  
  path: /root/img
# 开发环境  
img:  
  path: D:/桌面
# 主配置文件  
# 描述程序运行的平台的配置  
spring:  
  profiles:  
    active: prod

这样我们就根据配置文件读取信息

@Value("${img.path}")  
private String path;

2.设置文件名

  1. 先得到传输过来的整个文件名
  2. 获取文件后缀
  3. 生成一个随机的名字并和后缀名拼接起来
  4. 目录名+文件名拼接
@RequestMapping("/upfile")  
/**  
 * id:上传的是图片的id  
 * file必须是MutipartFile的,表示是一个  
 */  
public boolean upFile(Integer id , @RequestPart("img")MultipartFile file){  
    boolean result=false;  
    try {  
        //先获取整个传递过来的图片的名字  
        String fileName=file.getOriginalFilename();  
        //取图片的后缀  
        fileName=fileName.substring(fileName.lastIndexOf("."));  
        //将随机名和后缀组合成为一个新的图片名  
        fileName= UUID.randomUUID().toString()+fileName;  
        //目录名+图片名一起构成文件路径  
        file.transferTo(new File(path+fileName));  
        result=true;  
    } catch (IOException e) {  
        log.error(e.getMessage());  
    }  
    return result;  
}

得到Cookie

1.使用Servlet获取

因为SpringMVC是基于Servlet的,所以我们还是可以通过Servlet进行获取

得到Cookie数组之后遍历cookie

@RequestMapping("/getcookie")  
public void getCookie(HttpServletRequest request){  
    Cookie[] cookies =request.getCookies();  
    for (Cookie cookie:cookies) {  
        log.info(cookie.getName()+" "+cookie.getValue());  
    }  
}  

2.使用@CookieValue

注解里面是cookie的key,方法里面是value

@RequestMapping("/getcookie2")  
                    //@CookieValue里面是要查找的key值,方法的参数是对应的参数  
public void getCookie2(@CookieValue("bite") String value){  
    log.info("bite "+value);  
}

得到Header

1. 使用Servlet

使用HttpServletRequest的getHeader函数

@RequestMapping("/getheader")  
public void getHeader(HttpServletRequest request){  
    log.info("header: "+request.getHeader("User-Agent"));  
}  

2.使用@RequestHeader

使用@RequestHeader注解,里面是header的key.接收的是value

@RequestMapping("/getheader2")  
public void getHeader2(@RequestHeader("User-Agent") String value){  
    log.info(value);  
}

存储和获取session

存储session只有一个方法,就是使用HttpServletRequest

1.通过HttpServletRequest的getSession得到一个HttpSession对象,布尔值设置为true
2.通过HttpSession的setAttribute来设置session

@RequestMapping("/setsession")  
public void setSession(HttpServletRequest request){  
    HttpSession session=request.getSession(true);  
    if(session!=null) {  
        session.setAttribute("学习","概率论");  
    }  
}

使用Servlet获取Session

  1. 使用HttpServletRequest得到HttpSession
  2. 在使用HttpSession的getAttribute函数
@RequestMapping("/getsession")  
public String getSession(HttpServletRequest request){  
    HttpSession session=request.getSession(false);  
    if(session!=null&&session.getAttribute("学习")!=null){  
        return (String)session.getAttribute("学习");  
    }  
    return "暂无";  
}

使用@SessionAttribute

SessionAttribute注解(value=Session的key的值,required=false) session的value值

required表示可以没有这个Session对象

@RequestMapping("/getsession2")  
public String getSession2(@SessionAttribute(value = "学习",required = false) String value){  
    return value;  
}

返回数据

将后端的数据返回给前端,

默认返回静态页面

当没有@ResponseBody注解的时候,默认返回的是静态页面

  
@RequestMapping("/returnstatic")  
public Object returnStatic(){  
    return "/index.html";  
}  

返回text/html

@ResponseBody

返回对象

@RequestMapping("/returnbody")  
@ResponseBody  
public String returnBody(){return "

hello body

";}
@RestController

@RestController同时包含了@Controller和@ResponseBody

@Controller  
@ResponseBody  
public @interface RestController {

所以只要写一个注解就可以了,更加的方便

@RestController  
public class ControllerRest {  
    @RequestMapping("/print")  
    public String print(){return "Hello RestController";}  
}

使用Form表单进行交互

前端就是使用form传输数据,
input的name属性要和后端的方法的参数相同

前端:

DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>Titletitle>  
head>  
<body>  
    <form action="cal">  
        <input type="text" name="num1">  
        <input type="text" name="num2">  
        <input type="submit" value="提交">  
    form>  
  
body>  
html>

后端:

  
@RestController  
public class CalController {  
    @RequestMapping("/cal")  
    public Integer cal(Integer num1,Integer num2){return num1+num2;}  
}

返回JSON对象

直接返回HashMap对象就是返回的JSON对象

@RequestMapping("/json")  
public HashMap<String,String> returnJson(){  
    HashMap<String,String> hashMap=new HashMap<>();  
    hashMap.put("java","1");  
    hashMap.put("MySQL","2");  
    hashMap.put("Redis","3");  
    return hashMap;  
}

返回报文:

HTTP/1.1 200
Content-Type: application/json

接收JSON字符串

前端使用ajax发送JSON对象字符串到服务器,然后服务器再对这个JSON对象进行接收.

前端:

  1. html中有三个元素:name,password,sumbit
  2. 当点击sumbit按钮的时候,就触发JavaScript函数
  3. 使用ajax构造请求和JSON对象
  4. 要记住改一下传输的类型contentType:‘application/json’,要加上这个属性
  5. 当成功的时候返回结果
DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <meta http-equiv="X-UA-Compatible" content="IE=edge">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>Documenttitle>  
  
    <script src="jquery.min.js">script>  
head>  
<body>  
    <input type="text" class="name">  
    <input type="text" class="password">  
    <input type="button" value="提交" class="submit">  
    <script>  
        let name=document.querySelector(".name");  
        let password=document.querySelector(".password");  
        let submit=document.querySelector(".submit");  
        if(jQuery.trim(name.value)==""){  
            alert("输入为空,请重新输入");  
            name.focus();  
            return;  
        }  
        if(jQuery.trim(password.value)==""){  
            alert("输入为空,请重新输入");  
            password.focus();  
            return;  
        }  
        submit.onclick=function login(){  
            $.ajax({  
                type:'post',  
                url:'login',  
                contentType:'application/json',  
                data:JSON.stringify({  
                    name:jQuery.trim(name.value),  
                    password:jQuery.trim(password.value)  
                }),  
                success:function(body){  
                    if(body.succ==200){  
                        alert("body.name:"+body.name+" body.password:"+body.password);  
                    }else{  
                        alert("输入不完整");  
                    }  
                }  
            })  
        }  
    script>  
body>  
html>

后端:

  1. 因为传输过来的是一个JSON对象,所以再服务器也得有一个JSON对象People
  2. 并且要使用@RequestBody才可以接收到JSON对象
  3. 返回也是一个JSON对象,所以使用HashMap
@RequestMapping("/login")  
public HashMap<String,String> login(@RequestBody People people){  
    System.out.println(people.getName());  
    System.out.println(people.getPassword());  
    HashMap<String,String> hashMap=new HashMap<>();  
    int success=200;  
    if(people.getPassword()!=null&&people.getName()!=null){  
        hashMap.put("name",people.getName());  
        hashMap.put("password",people.getPassword());  
        hashMap.put("succ",success+"");  
    }else{  
        hashMap.put("succ","输入不完全");  
    }  
    return hashMap;  
}

接收JSON对象

上面我们是将JSON转为字符串了进行传递的,后端要使用@RequestBody People people进行接收

但是如果我们只传输JSON对象,不将它转为字符串,那么后端接收的时候直接按照参数进行接收就可以

前端:
直接传递JSON对象

data:{  
    name:jQuery.trim(name.value),  
    password:jQuery.trim(password.value)  
},

后端:
前端传递多少参数,就使用多少参数接收

@RequestMapping("/login2")  
public HashMap<String,String> login2(String name,String password){
}

转发forward

转发是服务器直接将要访问的内容返回

直接使用forward字符串

  1. 直接返回一个forward开头的字符串就可以
  2. 方法和类的前面不用加@ResponseBody,因为是转发网站
//    转发  
    @RequestMapping("/forward")  
    public String forward(){return "forward:/login.html";}

如果省略forword也可以,直接写网址也是可以的

使用Servlet转发

  1. 使用request的getRequestDispatcher(),里面填写要跳转的网址
  2. 再调用forward函数,里面是request和response
@RequestMapping("/forward2")  
public void forward2(HttpServletRequest request, HttpServletResponse response){  
    try {  
        request.getRequestDispatcher("/cal.html").forward(request,response);  
    } catch (ServletException e) {  
        e.printStackTrace();  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
}

重定向redirect

重定向相当于是只给了一个网址,还需要我们手动的在去访问

也就是说服务器只是返回了一个新的网址,客户端进行新的网址的访问

使用redirect字符串

和forward一样,都是使用redirect开头

@RequestMapping("/redirect")  
public String redirect(){  
    return "redirect:/cal.html";  
}

使用Servlet

使用HttpServletResponse的sendRedirect直接进行转发

@RequestMapping("/redirect2")  
public void redirect2(HttpServletResponse response){  
    try {  
        response.sendRedirect("/cal.html");  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
}

Redirect和forward的区别

  1. 转发的对象不同
    forword的转发对象是服务器.redirect转发的对象是客户端
  2. url不同
    forword直接是将内容返回了,所以还是那个url,但是redirect是重新访问了一个新的网址
  3. 共享资源不同
    forward的两次都共享一个资源,但是因为redirect都转发了两次,所以共享不同的资源
  4. 安全性不同
    forward所带有的资源可能会因为路径的问题加载不出来,redirect不会
  5. 请求转发次数不同
    forward只请求转发1次,redirect请求转发了2次

你可能感兴趣的:(框架,java,spring,servlet,SpringMVC,Jquery)