Spring MVC

1. Spring MVC概述

SpringMVC是Spring的一个模块,是一个基于MVC(Model-View-Controller)设计模式的web框架。

2. Spring MVC执行流程

组件分析:

  • 前端控制器(默认配置 ):分发请求,统一处理请求和响应

  • 处理器映射器(默认配置):根据配置的映射规则(根据请求的URL),找到对应的处理器

  • 处理器适配器(默认配置):适配调用具体的处理器,并且执行处理器中处理请求的方法

  • 处理器(需要开发)

  • 视图解析器:会根据传递过来的ModelAndView对象进行视图解析,根据视图解析名解析称真正的视图View

  • 视图:View是一个接口,它的实现类支持不同类型的视图。比如:JSP、freemarker、Thymeleaf等等。

3. Handler

引入SpringMVC依赖

复制代码
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.1 接收请求参数

  • 简单类型的参数,Spring MVC可以直接帮我们封装成参数列表中声明的类型,比如String、int、double......

    java 复制代码
    //http://localhost:8080/login?username=zs&password=123
    @RequestMapping("/login")
    public void login(String username, String password){
        System.out.println(username);
        System.out.println(password);
    }
  • 或者也可以直接接收一个Java Bean

    java 复制代码
    //http://localhost:8080/login?name=zs&age=23&birthday=2020-02-02
    @RequestMapping("/login")
    public void login(Person person) {
         System.out.println(person.getName());
         System.out.println(person.getAge());
    }
  • 如果请求参数是一个日期,Spring MVC并不能直接封装到Date中,需要设置一下日期格式。

    java 复制代码
    public class Person{
        private String username;
        private String password;
        @DateTimeFormat(pattern = "yyyy-MM-dd")//前端到后端 可以把前端string类型转换到后端date类型
        //@JsonFormat(pattern = "yyyy-MM-dd")//后端到前端   可以把后端date类型转换到前端string
        private Date birthday;
        // getters & setters...
    }
  • 如果请求参数是一个数组类型,我们可以直接通过数组接收。

    java 复制代码
    http://localhost:8080/delSel?ids=1&ids=2    请求参数ids为方法的参数
    @RequestMapping("delSel")
    public String delSel(Integer[] ids) {
        System.out.println(Arrays.toString(ids));
        return "index";
    }
  • 如果想要用集合类型来接收数组参数,需要加上**@RequestParam**注解

3.2 获取servletAPI

可以在Handler的形参中直接使用以下类型:

  • HttpServletRequest 通过request对象获取请求信息

  • HttpServletResponse 通过response处理响应信息

  • HttpSession 通过session对象得到session中存放的对象

java 复制代码
 @RequestMapping("servletTest")
    public void servletTest(
            HttpServletRequest request,
            HttpServletResponse response,
            HttpSession session
    ) throws IOException 
    {
        System.out.println(request.getContextPath());
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("我是");
        System.out.println(session.getId());
​
    }

3.3 返回值

可以为Handler指定两种种返回值类型:

  • void

    如果返回值为void的时候,可以在Handler形参上定义requestresponse,使用requestresponse指定响应结果

  • String

    逻辑视图名称

    返回的字符串就是逻辑视图。

    java 复制代码
    @RequestMapping("login2")
        public void login2(HttpServletRequest request, HttpServletResponse response) throws IOException {
            String username = request.getParameter("username");
            System.out.println(username);
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().println("返回值");
        }
    ​
    ​
    @RequestMapping("/login3")
    public String login3() {
        //return "forward:/login1";//可以请求转发到另一个handler
        //return "forward:/index.jsp";//可以请求转发到另一个jsp
        return "redirect:/index.jsp";//可以重定向到另一个jsp 注意观察地址栏
    }

3.4 注解

  1. @Controller:用于声明一个类为Spring MVC的控制器。控制器负责处理用户请求。

    @Controller
    public class TestController1 {
        // ...
    }
    
  2. @RequestMapping:用于将HTTP请求映射到控制器的方法上。可以指定请求路径、请求方法等。

    @RequestMapping(value = "/login1", method = RequestMethod.GET)
    public String login(Person person) {
        // ...
    }
    
  3. @RequestParam @RequestParam:用于将请求参数绑定到控制器方法的参数上。可以指定参数名、是否必须、默认值等。

    该注解用来标注一个请求参数:

    在方法的形参前,可以加可以不加,加了就有特殊含义了

    java 复制代码
    @RequestMapping(value = "/login3")
    public String login3(String name) {
        System.out.println(name);
        return "index";
    }
    
    //上述方式在请求 login3 可以不强制传递请求参数,那打印name结果是null
    @RequestMapping(value = "/login3")
    public String login3(@RequestParam String name) {
         System.out.println(name);
         return "index";
    }
    
    //上述方式在请求 login3 强制必须传递请求参数,那打印name结果就是请求参数传的值
    //http://localhost:8080/login3?name1=tom
    @RequestMapping(value = "/login3")
    public String login3(@RequestParam("name1") String name) {
        System.out.println(name);
        return "index";
    }
    
    //required = false,默认是true 代表着必须传递参数,如果设置false代表可以不传递参数
    @RequestMapping(value = "/login3")
    public String login3(@RequestParam(name = "name1",defaultValue = "zs") String name) {
      System.out.println(name);
      return "index";
    }
    
    //设置默认值,这样required就不需要在写了。
    public String login(@RequestParam(value = "username", required = true, defaultValue = "noname") String name)
    value:@RequestParam(value="username")等同于@RequestParam("username")
    required:参数是否必填
    defaultValue:设置默认值 
    
  4. @PathVariable:用于将URL中的占位符参数绑定到控制器方法的参数上。

    将路径的一部分作为请求参数,RESTful的基础。

    java 复制代码
    //http://localhost:8080/findById/1
    @RequestMapping("/findById/{id}")
    public String findById(@PathVariable Integer id) {
       System.out.println(id);
       return "index";
    }
    //请求参数就不可以是?号。参数必须是目录形式。

    RESTful就是一个url的编写风格。使用RESTful就不需要用❓问号分割请求参数了。

    一个严格的RESTful中是不可能存在❓的。

    一个URl对应一个资源,请求方式确定一个动作。

    ps:有一张person表id有1 2 3 ,name有zs,lisi,wangwu。

    POST请求:就是向数据库中添加数据。/person,代表把person对象添加到表中

    DELETE请求:就是向数据库中删除一条数据。 /person/1 ,代表把person表中id为1的 删除

    PUT请求:就是向数据库修改一条数据。/person/1,代表把person表中id为1的 修改

    GET请求:就是向数据库表查询数据。/person/3, 代表把person表中id为3的 查询出来

  5. @ResponseBody:用于将控制器方法的返回值作为HTTP响应的正文返回,而不是返回一个视图。

    @RequestMapping("/hello")
    @ResponseBody
    public String hello() {
        return "Hello, World!";
    }
    
  6. @RequestBody:用于将请求正文绑定到控制器方法的参数上,通常用于处理JSON或XML格式的请求数据。

    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody Person person) {
        // ...
    }
    
  7. @RestController:是@Controller和@ResponseBody的组合注解,用于声明一个类为REST风格的控制器。

    @RestController
    public class TestRestController {
        // ...
    }
    
  8. @GetMapping@PostMapping@PutMapping@DeleteMapping:分别用于处理GET、POST、PUT、DELETE请求的快捷方式。

    @GetMapping("/users")
    public List<User> getUsers() {
        // ...
    }
    

4. 静态资源访问

springboot中放置静态资源的目录,常用有static和templates目录,只要把静态资源放到这几个目录下,就能直接访问到

复制代码
http://localhost:8080/login.html
复制代码
http://localhost:8080/login1.html 

static目录下静态资源默认是可以被访问到的,但是templates目录下资源默认是访问不到的,需要做配置:

复制代码
spring.web.resources.static-locations=classpath:/templates

也可以直接给所有静态资源添加一个前缀,既可统一拦截,又可统一放开

复制代码
spring.mvc.static-path-pattern=/res/**
复制代码
http://localhost:8080/res/login1.html 

5. 文件上传

5.1 同步表单上传

添加fileupload依赖

复制代码
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

配置

在配置文件中添加上传文件最大值

复制代码
# 开启文件大小配置 默认值true
spring.servlet.multipart.enabled=true
#单个文件数据大小
spring.servlet.multipart.max-file-size=2048MB
#总数据的大小
spring.servlet.multipart.max-request-size=2048MB
​
​
1 Byte = 8 Bits
1 Kilobyte (KB) = 1024 Bytes
1 Megabyte (MB) = 1024 KB
1 Gigabyte (GB) = 1024 MB
1 Terabyte (TB) = 1024 GB
1 Petabyte (PB) = 1024 TB
1 Exabyte (EB) = 1024 PB
1 Zettabyte (ZB) = 1024 EB
1 Yottabyte (YB) = 1024 ZB

form表单

java 复制代码
<form action="/file/fileUpload" method="post" enctype="multipart/form-data">
    图片上传:  <input type="file" name="img">
    <br>
    <button>上传</button>
</form>

Controller编写

java 复制代码
@Controller
public class FileController {
​
    @PostMapping("/file/fileUpload")
    public String fileTest(MultipartFile img) {
        System.out.println(img.getSize());
        System.out.println("文件上传");
        return "redirect:/index.html";
    }
}

测试

复制代码
http://localhost:8080/login.html

5.2 高级上传

需求:跨服务器上传图⽚,⻚⾯不刷新,图⽚即时回显。

⻚⾯不刷新:AJAX

图⽚即时回显:

复制代码
<img src=""/> 

先导入依赖

复制代码
<dependency>
   <groupId>io.minio</groupId>
   <artifactId>minio</artifactId>
   <version>8.4.1</version>
</dependency>

编写form表单

java 复制代码
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
    <script src="js/jquery.form.min.js"></script>
​
</head>
<body>
​
<form id="form1">
    图像:
    <input type="file" name="f" onchange="doUpload()" style="display:none">
    <br>
    <img id="img1" width="100px " src="https://oss.coding-future.com:9000/fileupload/icon.JPG" onclick="selectImg()">
</form>
​
</body>
​
<script>  
    function doUpload() {
        console.log("图片被点击了");
        //异步提交表单
        $('#form1').ajaxSubmit({
            url: '/file/fileUploadAdv',
            type: 'post',
            success: function (data) {
              $("#img1").prop("src", data)//修改src属性
            }
        })
    }
​
    function selectImg() {
        $('input[name="f"]').click();
    }
</script>
</html>

Controller

java 复制代码
@Controller
public class FileController {
​
    @PostMapping("/file/fileUploadAdv")
    public void fileUpload(@RequestParam("f") MultipartFile f) throws Exception {
​
        MinioClient client = MinioClient.builder()
                .endpoint("https://oss.coding-future.com:9000")
                .credentials("student", "12345678")
                .build();
​
        client.putObject(
                PutObjectArgs.builder().
                        bucket("fileupload").
                        object(f.getOriginalFilename()).
                        stream(f.getInputStream(), f.getSize(), -1)
                        .contentType(f.getContentType())
                        .build());
    }
}

6. 拦截器

javaweb三大组件:servlet、filter、listener

6.1创建拦截器

实现HandlerInterceptor接口

java 复制代码
/**
 * 创建拦截器
 */
public class LoginInterceptor implements HandlerInterceptor {
​
    //该方法在handler处理请求之前被调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //return true;//拦截失败 通过
        return false;//拦截成功,不通过
    }
​
    //该方法在当前handler处理之后,也就是Controller方法被调用之后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,    
                            ModelAndView modelAndView) {
    }
​
        // 在页面渲染之后进行处理
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
                                Object handler, Exception ex) {
    }
}

6.2 配置拦截器

java 复制代码
//将配置注入容器
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
               registry.addInterceptor(new LoginInterceptor())
                //拦截所有资源
                .addPathPatterns("/**")
                //将指定资源放行
                .excludePathPatterns("/index.html", "/login","/js/**");
    }
}

6.3 简单实现

java 复制代码
public class LoginInterceptor implements HandlerInterceptor {
​
​
    /**
     * 在接口调用前 执行
     *
     * @param request
     * @param response
     * @param handler
     * @return true 放行 不拦截  否则...
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  {
        HttpSession session = request.getSession();
        Object username = session.getAttribute("username");
        if (username != null) {
            //放行
            return true;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("code", 403);
        map.put("data", "list");
        map.put("message", "success");
        String data = JSON.toJSONString(map);
        response.getWriter().println(data);
        retrn false;
    }
}
相关推荐
m0_748235241 天前
前端实现获取后端返回的文件流并下载
前端·状态模式
委婉待续1 天前
java抽奖系统(八)
java·开发语言·状态模式
m0_748241122 天前
前端监控之sourcemap精准定位和还原错误源码
前端·状态模式
m0_748245172 天前
前端下载文件的几种方式使用Blob下载文件
前端·状态模式
m0_748236583 天前
前端如何将pdf等文件传入后端
前端·pdf·状态模式
MatthewMao3 天前
设计模式12:状态模式
设计模式·状态模式
小白64023 天前
浅谈目前我开发的前端项目用到的设计模式
前端·设计模式·状态模式
xyz20116 天前
Flink State面试题和参考答案-(下)
flink·状态模式
方圆想当图灵6 天前
问题解决:发现Excel中的部分内容有问题。是否让我们尽量尝试恢复? 如果您信任此工作簿的源,请单击“是”。
excel·状态模式
攻心的子乐8 天前
satoken 后端获取用户id的原理是啥 用了前端传的那个参数
前端·状态模式