Spring MVC程序开发

所谓的Spring MVC程序开发,其实也是一个Spring Boot项目。

MVC是Model View Controller的缩写,它是软件工程中的一种软件架构模式,它把软件系统分为模型,视图,控制器三个部分。

项目使用什么技术实现的??

  1. SSM项目 Spring + Spring MVC + Mybatis(中期)

    Spring Boot + Spring web(Spring MVC)+ Mybatis(现在)

  2. SM项目 Spring Boot(Spring web)+ Mybatis(现在)
  1. Spring MVC是一个Web框架
  2. Spring MVC是基于Servlet API构建的

MVC和Spring MVC的关系:

MVC是一种思想,而Spring MVC是对MVC思想的具体实现。

总结来说,Spring MVC是一个实现MVC模式,并继承了Servlet API的Web框架,既然是Web框架,那么当用户在浏览器输入url之后,我们的Spring MVC项目就可以感知到用户的请求。

现在绝大部分Java项目,都是基于Spring(或者Spring Boot)的,而Spring的核心就是Spring MVC。

Spring MVC是Spring框架的核心模块,Spring Boot是Spring的脚手架

怎么学Spring MVC?

学习Spring MVC我们只需要掌握以下3个功能:

  1. 连接的功能,将用户(浏览器)和Java程序连接起来,也就是访问一个地址能够调用到我们的Spring程序。
  2. 获取参数的功能,用户访问的时候会带一些参数,在程序中要想办法获取到。
  3. 输出数据的功能,执行了业务逻辑之后,要把程序执行的结果返回给用户。

对于Spring MVC来说,掌握了以上3个功能,就相当于掌握了Spring MVC。

创建Spring MVC项目:

在2018年之前,使用Maven项目添加Spring MVC框架的方式来进行创建(复杂,太麻烦),现在我们来使用Spring Boot来创建Spring MVC项目!

创建的时候,选择lombok,Spring Web(可添加Spring MVC框架),Spring Boot DevTools(热部署)。

@RestController  //@RestController = @ResponseBody + @Controller
//通过注解
public class UserController {
    @RequestMapping("/say")  //一级路由,可设置多级路由
    public String sayHi(){
        return "hi Spring MVC";
    }
}

在上述代码中,我们使用了: @RequestMapping("/say"),该注解支持GET,POST,PUT,DELETE等请求。

如下述仅支持POST类请求的代码:

    @RequestMapping(Value = "/sayhi", method = RequestMethod.POST)

    //这两个都可表示仅仅支持POST类请求:

    @PostMapper("/sayHello")
    public String sayHello() {
        return "hello Spring MVC ";
    }

如下述仅支持GET类请求的代码:

    @GetMapper("/hi")
    public String sayHello() {
        return "hi Spring MVC ";
    }

获取参数:

获取一个参数:

@RestController
public class UserController {

    @RequestMapping("/sayHi")
    public String sayHi(String name){
        return "hi " + name;
    }

}

参数传递建议不要使用基础数据类型(容易报错),建议使用包装类

在浏览器输入:localhost:8080/sayHi?name=zhangsan(注意:参数名name一定要相同,否则会出错)

获取多个参数:

具体代码可参考获取一个参数的代码!

@RestController
public class UserController {

    @RequestMapping("/sayHi")
    public String sayHi(String name,String password){
        return "hi " + name +" " + password;
    }

}

在浏览器输入:localhost:8080/sayHi?name=zhangsan&password=123456

获取对象:

首先,我们来自定义一个对象吧!

@Data  //@Data丰富java自动资源管理,自动生成getter、setter、equals、hashCode和toString等
public class Userinfo {
    private int id;
    private String name;
    private String password;
    private int age;
}

获取参数代码:

@RestController
public class UserController {
    
    @RequestMapping("/reg")
    public Object reg(Userinfo userinfo){  //框架会实现自动的参数映射
        System.out.println(userinfo);
        return userinfo;
    }

}

在浏览器输入:localhost:8080/reg?name=zhangsan&password=123456&id=1&age=18(框架会实现自动的参数映射)

当然,也可以获取一个HTML标签:

获取一个HTML标签:

@RestController
public class UserController {

    @RequestMapping("/he")
    public Object getHe(){
        return "<h1>我是HTML中H1标签</h1>";
        //HTML的标签
    }

}

在浏览器中输入:localhost:8080/he

后端参数重命名:

@RestController
public class UserController {

    @RequestMapping("/reg2")
    public Object reg(@RequestParam("username")String name,String password){
        //将前端传递来的名称(username)改为name(后端)
        //必传参数username
        return name+" "+password;
    }
    
}

在上述代码中:

前端传递的参数username(必传参数)

后端使用的参数name

意思是:将前端传递来的参数username被后端更改为name

在浏览器中输入:localhost:8080/reg2?username=zhangsan&password=123456

在上述代码中:username属于必传参数,当然也可以变为非必传参数,如果不传的话,默认为null

@RestController
public class UserController {

    @RequestMapping("/reg2")
    public Object reg(@RequestParam(value = "username",required = false)String name,String password){
        //将前端传递来的名称(username)改为name(后端)
        //必传参数username
        return name+" "+password;
    }

}

在浏览器中输入:localhost:8080/reg2?password=123456

获取JSON对象:

在这个操作中,我们来借助Postman来进行操作:

@RestController
public class UserController {
    @RequestMapping("/reg3")
    public Object reg3(@RequestBody  Userinfo userinfo){
        return userinfo;
    }
}

在Postman中,我们通过:Body------》raw------》JSON------》设置参数------》sign来进行操作:

所设置的参数为:

{
    "id":"1",
    "name":"zhangsan",
    "password":"123456",
    "age":"18"

}

运行程序,并点击sign后端的相应为:

从基础URL中获取参数:

从基础URL中获取参数(不是URL的参数部分的参数)

@RestController
public class UserController {

    @RequestMapping("/reg4/{name}/{password}")
    public Object reg4(@PathVariable String name,@PathVariable("password")String password){
        return "name = "+name+" | password ="+password;
    }
    
}

在浏览器中输入:localhost:8080/reg4/zhangsan/123456(顺序需要一一对应)

当然,对于上述的必需参数,也可以更改为非必须参数:

@RestController
public class UserController {

    @RequestMapping("/reg4/{name}/{password}")
    public Object reg4(@PathVariable String name,@PathVariable(required = false,name = "password")String password){
        return "name = "+name+" | password ="+password;
    }

}

那么,我们来看一下注解@PathVariable和注解@RequestParm吧!

  1. 注解@PathVariable:基础URL里面的参数(?之前的参数)
  2. 注解@RequestParm:URL参数部分的参数(?之后的参数)

http://localhost:8080/reg4?name=zhangsan&password=123456

获取上传图片:

@RestController
public class UserController {
    @RequestMapping("myupload")
    public Object upload(@RequestPart("mying")MultipartFile file){
        //@RequestPart("mying")拿到请求的文件,赋值给MultipartFile file
        File saveFile=new File("D:\\Data\\mying.png");
        //D:\Data\mying.png想要将请求的文件上传到的路径
        //mying.png上传后的文件名
        try {
            file.transferTo(saveFile);
            return true;//上传成功
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;//上传失败
    }

}

本次也通过Postman来进行操作:

Boby,form-data,mying右侧选择file,mying.png

当然,在这个过程中,我们需要注意图片的大小,太大就容易上传失败(可以在配置文件中自行设置图片的最大范围)

spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB

最后的结果为:

那么,接下来又有个问题:

后面再次上传的图片会覆盖前面的图片,名称为:mying.png

因此,我们可以在获得的原文件名的后缀带有一个独一无二的UUID,那么这个问题不就解决了吗??

        String fileName= UUID.randomUUID()+ //文件名
                file.getOriginalFilename().substring(  //源文件进行分割
                        file.getOriginalFilename().lastIndexOf(".")); //添加后缀
        File saveFile=new File("D:\\Data\\"+fileName);

通过上述的代码即可。

因此总的代码为:

@RestController
public class UserController {
    @RequestMapping("myupload")
    public Object upload(@RequestPart("mying")MultipartFile file){
        //@RequestPart("mying")拿到请求的文件,赋值给MultipartFile file

        String fileName= UUID.randomUUID()+ //文件名
                file.getOriginalFilename().substring(  //源文件进行分割
                        file.getOriginalFilename().lastIndexOf(".")); //添加后缀
        File saveFile=new File("D:\\Data\\"+fileName);

      //  File saveFile=new File("D:\\Data\\mying.png");
        //D:\Data\mying.png想要将请求的文件上传到的路径
        //mying.png上传后的文件名
        try {
            file.transferTo(saveFile);
            return true;//上传成功
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;//上传失败
    }

}

当我们重新运行程序,再次上传图片的时候:

因此,这样才能多次获取新的图片,并且每次都能成功的保存下来!

获取Cookie

1.获取单个Cookie

@RestController
public class UserController {
    @RequestMapping("/getck")  //获取名称为java的Cookie,并赋值给java
    public Object getCk(@CookieValue(value ="java",required = false)String java){
        return java;
    }
}

2.获取所有Cookie

@RestController
public class UserController {

    @RequestMapping("/getck")
    public String getCk(HttpServletResponse response,HttpServletRequest request){
        String name=request.getParameter("name");
        //获取所有Cookie信息
        Cookie[] cookies=request.getCookies();
        return name+" 你好! ";
    }
}

获取Header中的某个信息:

@RestController
public class UserController {

   @RequestMapping("/gethd")
    public Object getHeader(@RequestHeader("User-Agent")String ua){
       return "header---->" + ua;
   }

}

在浏览器中输入:http://localhost:8080/gethd

运行结果为:

获取Session:

在获取Session之前,一定要进行存储Session,才能进行获取,存Session没有捷径可走,不能通过注解的方式实现。

什么时候才会有Session的存储??只有当用户的用户名和密码都正确的情况下,才会存储Session。

在Servlet阶段,如何存储Session,那么,在现阶段也是如何存储Session的!!

@RestController
public class UserController {
    //定义全局变量
    private static final String SESSION_KEY="USERINFO_SESSION";

    //存储Session
    @RequestMapping("/setsess")
    public void setSess(HttpServletRequest request){
        HttpSession session=request.getSession();
        session.setAttribute(SESSION_KEY,"zhangsan");
    }

    //获取session
    @RequestMapping("/getsess")
    public Object getSession(@SessionAttribute(SESSION_KEY)String name){ //赋值给name
        return "session + "+name;
    }

}

在浏览器中输入:http://localhost:8080/getsess

返回数据:

1.返回静态页面:

Java后端代码:

@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/index")
    public Object getIndex(){
        return "/index.html"; //静态页面(VSCode)
//加个"/"(斜杠)表示从根路径取找index.html
//如果不加斜杠,则会404报错
    }
}

HTML静态页面代码:

<!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>Document</title>
</head>
<body>
<h1 style="color: red">我是 index.html</h1>
</body>
</html>

在浏览器输入:localhost:8080/test/index

请求转发和重定向:

请求转发和重定向:forward VS redirect

return不但可以返回一个视图,还可以实现跳转,跳转的方式有两个:

  1. forward :请求转发

  2. redirect :请求重定向

    @Controller
    @RequestMapping("/test")
    public class TestController {
    //请求转发
    @RequestMapping("/fw")
    public String fw(){
    return "forward:/index.html";
    }
    //浏览器输入localhost:8080/test/fw

     //请求重定向
     @RequestMapping("/rd")
     public String rd(){
         return "redirect:/index.html";
     }
     //浏览器输入localhost:8080/test/rd会跳转到localhost:8080/index.html
    
     //请求重定向到百度《------》另一种写法
     @RequestMapping("/rd2")
     public void rd2(HttpServletResponse response) throws IOException{
         response.sendRedirect("https://www.baidu.com/");
     }
     //浏览器输入localhost:8080/test/rd2会跳转到百度
    

    }

复制代码
浏览器输入localhost:8080/test/fw
复制代码
浏览器输入localhost:8080/test/rd会跳转到localhost:8080/index.html
复制代码
浏览器输入localhost:8080/test/rd2会跳转到百度

请求转发forward和请求重定向redirect的区别!!(面试题)

  1. 定义不同
  2. 跳转方不同
  3. 数据共享不同
  4. 最终URL不同
  5. 代码实现不同
  6. ........................
相关推荐
喵叔哟8 分钟前
重构代码之移动字段
java·数据库·重构
喵叔哟8 分钟前
重构代码之取消临时字段
java·前端·重构
fa_lsyk10 分钟前
maven环境搭建
java·maven
Daniel 大东29 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
wind瑞36 分钟前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen36 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)41 分钟前
读写锁分离设计模式详解
java·设计模式·java-ee
鸽鸽程序猿42 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
修道-032343 分钟前
【JAVA】二、设计模式之策略模式
java·设计模式·策略模式
九圣残炎1 小时前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode