SpringMVC模型

文章目录

SpringMVC模型

一、概念

MVC模型:M(模型)、V(视图)、C(控制器),是一种架构模式

模型:领域对象 - 具体业务,区分:实体类不跟业务

​ 模型包含:实体类、业务逻辑sevice

​ 后台操作都是在模型中

视图:把信息显示给用户

控制器:是模型和视图的桥梁,从视图接收数据,封装成对象,传给后台(模型)

二、配置

第一:添加MVC模型需要的依赖

<dependencies>
        <!-- 添加servlet依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- 添加webmvc依赖,会将Spring的核心包一并依赖进来 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.23</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.5</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
    </dependencies>

  

第二:添加war插件

注意:在有web包的文件设置<packaging>war</packaging> 属性

  <build>
        <plugins>
            <!-- war插件 -->
            <plugin>
               <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
                <configuration>
                    <warSourceDirectory>wab</warSourceDirectory>
                    <webXml>web/WEB-INF/web.xml</webXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

第三:添加web文件

在这里插入图片描述

第四:配置web.xml文件

添加核心请求总控器

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 核心请求总控器,负责接收所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- springmvc默认会从WEB-INF目录下查找名为[servletName]-servlet.xml的配置文件,
             这是spring官方默认的约定命名。如果想要自定义文件名并且想存放在其他目录下,
             则需要通过contextConfigLocation初始化参数来配置,
             例如:自定义一个springmvc.xml配置文件放在resources目录下
        -->
<!--        <init-param>-->
<!--            <param-name>contextConfigLocation</param-name>-->
<!--            <param-value>classpath:springmvc.xml</param-value>-->
<!--        </init-param>-->

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

第五:配置dispatcher-servlet.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--启用注解扫描 -->
    <context:component-scan base-package="edu.nf.ch01"/>
    <!-- 启用mvc注解处理器
         这个注解驱动注册了RequestMappingHandlerMapping(请求映射处理器)
         和一个RequestMappingHandlerAdapter(请求处理适配器),同时
         提供了@ReqeustBody、@ResponseBady注解支持、数据绑定等支持 -->
    <mvc:annotation-driven/>

    <!--配置视图解析器,springmvc支持多种视图,不同的视图由不同的视图解析器来解析
    例如:想要使用JSP作为视图,那么就需要配置InternalResourceViewResolver这个视图解析器,用于解析内部的JSP资源 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 设置JSP资源的前缀,用于指定jsp存放的目录 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 设置jsp资源的后缀名,以'.jsp'结尾的文件-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

三、springmvc的请求注解及配置方法

1. @RequestMapping

  • 声明在方法上,设置请求地址和请求类型
  • 声明在类上,用作命名空间,可以区分多个相同子请求
package edu.nf.ch02.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Date 2023-10-19
 * @Author hy
 */
@Controller
/**
 * @RequestMapping注解可以声明在类上,用作命名空间
 * 可以区分多个相同子请求
 */
@RequestMapping("/admin")
public class RequestMapController {

    // 设置请求地址和请求类型
    @RequestMapping(value = "/getUser", method = RequestMethod.GET)
    public ModelAndView getUser(){
       // 响应视图,JSP视图解析器基于转发的机制
        return new ModelAndView("index");
    }

    @RequestMapping(value = "/login", method = {RequestMethod.POST,RequestMethod.GET})
    public ModelAndView login(){
        return new ModelAndView("index");
    }
}

从springmvc4.0开始,提供了新的子注解来替换@RequestMapping

2. @GetMapping

与@RequestMapping作用一样,只是@GetMapping只能用于get请求

package edu.nf.ch02.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Date 2023-10-19
 * @Author hy
 */
@Controller
public class RequestMapController {

    /**
     * @GetMapping只能用于get请求
     * @return
     */
    @GetMapping("/getUser2")
    public ModelAndView getUser2(){
        return new ModelAndView("index");
    }
}

3. @PostMapping

与@RequestMapping作用一样,只是@PostMapping只能用于post请求

package edu.nf.ch02.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Date 2023-10-19
 * @Author hy
 */
@Controller
public class RequestMapController {

    /**
     * @PostMapping只能用于post请求
     * @return
     */
    @PostMapping("/login2")
    public ModelAndView login2(){
        return new ModelAndView("index");
    }
}

四、SpringMVC原理解析

在这里插入图片描述

1. DispatcherServlet (核心请求总控器)

DispatcherServlet是SpringMVC的核心控制器,负责截获所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理

springmvc执行流程:

浏览器发起请求,会被中央调度器(DispatcherServlet)所捕获,但中央调度器不会直接去处理请求,而是把请求交给 处理器映射器(HandlerMapping)处理,处理器映射器根据请求的路径(url地址)去Controller控制层中进行匹配[即对应的执行器:找到哪一个Controller的方法可以处理该请求],然后将匹配结果(整个Controller)返回给中央调度器;中央调度器再调用处理器适配器(HandlerAdaptor)来执行匹配结果(控制层执行器)的方法并返回执行结果(即ModelAndView对象)给中央调度器,

中央调度器会将返回的ModelAndView对象交给视图解析器(ViewResolver)解析成对应的视图(View)对象,渲染视图,最后将结果响应给浏览器。

2. HandlerMapping和HandlerAdapter

当xml配置了 注解处理器<mvc:annotation-driven/> 或者 配置类中配置了@EnableWebMvc注解时,spring会自动装配 RequestMappingHandlerMapping(请求映射处理器)、RequestMappingHandlerAdapter(请求处理适配器)这两个类。

  • RequestMappingHandlerMapping: 负责解析带有 @ReqeustMapping 注解的方法以及类信息,并在请求到达时找到相应的 HandlerMethod(一个 JavaBean,封装了请求处理方法、参数信息、类信息以及 IOC 容器等重要的内容)。

    当找到相应的 HandlerMethod 后,如果程序中有定义拦截器,那么就会将这个 HandlerMethod 封装到 HandlerExecutionChain 的类中,这个类包含了一个 拦截器的集合 和一个 HandlerMethod 的对象。最后将这个 chain 返回给 DispatcherServlet 。
    DispatcherServlet 从这个 HandlerExecutionChain 中取出 HandlerMethod 来匹配相应的 HandlerAdapter,找到合适的可以调用 HandlerMathod 的请求处理适配器。
    接着 DispatcherServlet 负责调用 HandlerExecutionChain 中的所有拦截器中的预处理方法,如果预处理方法没有任何问题,那么就将 HandlerMethod 交给 HandlerAdapter 去调用。

  • RequestMappingHandlerAdapter: DispatcherServlet 将 HandlerMethod 传递给 HandlerAdapter,由它负责调用 HandlerMethod(也就是目标控制器的方法)。

    调用时还会使用具体的 MethodArgumentResolver (方法参数解析器, RequestMappingHandlerAdapter 内部会初始化一系列默认的 HandlerMethodArgumentResolver)将请求中的参数解析为请求处理方法所需要的具体类型参数。
    最后将 Controller 方法返回的 ModelAndView 一并返回到 DispatcherServlet 中。
    接着 DispatcherServlet 会继续执行所有拦截器中的后置处理方法。

3. ViewResolver

springmvc内部提供了许多视图解析器用于解析不同的视图对象,最长见的有InternalResourceViewResolver(内部资源视图解析器)、FreeMarkerViewResolver(模板引擎视图解析器)等。

InternalResourceViewResolver
在 DispatcherServlet 接收到 HandlerAdapter 返回的 ModelAndView 之后,DispatcherServlet 将这个 ModelAndView 交给指定InternalResourceViewResolver 来进行视图解析,
InternalResourceViewResolver 会根据ModelAndView 的视图名称来创建一个 InternalResourceView 的视图对象返回到 DispatcherServlet。由 DispatcherServlet 去调用视图对象的渲染方法来响应视图。
在渲染完视图之后,DispatcherServlet会执行所有拦截器中的after方法。

4. View

视图对象是由相应的视图解析器解析出来的,Spring也提供了不同的视图对象来完成不同的视图响应工作,常见的有的InternalResourceView(内部资源转发视图)等。

InternalResourceView: 这个视图对象会将 ModeAndView 中而外带的数据放入请求作用域,以及获取到拼接好的转发地址。并提供一个 renderMergedOutputModel 渲染方法由 DispatcherServlet 调用,这个方法就是负责具体的url转发工作。

五、springmvc处理静态资源的方式

1. 使用容器的默认Servlet来处理

  <!-- 方式一  将静态资源交给容器的默认Servlet来处理,springmvc不参与解析。
       常见的servlet容器如Tomcat、Jetty等都会有一个自带的DefaultServlet来处理这些静态资源 -->
  <mvc:default-servlet-handler/> 

2. 由springmvc自己来处理

 <!--  方式二  静态资源由springmvc自己来处理
       mapping:用于映射静态资源的虚拟url; 
       location:用于指定静态资源的本地相对路径;
      例如:下面的配置中,当以page为开头的所有请求,都会映射到static这目录中去查找相应的静态资源文件 -->
 <mvc:resources mapping="/page/**" location="/static/"/>

六、创建web文件

快速在webapp文件夹下创建web文件

第一:添加依赖
 <packaging>war</packaging>
第二:创建webapp文件夹

在项目的.\src\main\路径下,创建一个webapp文件夹

第三:手动添加web文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意:用此方法创建web文件,不能再添加web插件依赖(二选一)

七、SpringMVC中请求参数绑定

第一:创建web文件

第二:添加依赖

 <packaging>war</packaging>

第三:配置dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 扫描 -->
    <context:component-scan base-package="edu.nf.ch04"/>

    <!-- 启用mvc注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 默认servlet处理静态资源处理 -->
    <mvc:resources mapping="/page/**" location="/static/"/>

    <!-- 内部资源视图解析器
         一般添加了hibernate-validator依赖,就不需要再配置内部资源视图解析器,
         只有在自定义路径、重定向时才需要配置
     -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 设置JSP资源的前缀,用于指定jsp存放的目录 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 设置jsp资源的后缀名,以'.jsp'结尾的文件-->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

第四:配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 配置核心请求总控器,负责接收所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

第五:创建一个静态页面,添加用户

路径:webapp/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>添加用户</h2>
<form id="f1" method="post" action="../add3">
  Name:<input type="text" name="username" value="simi"/><br>
  Age:<input type="text" name="age" value="21"/><br>
  Birth:<input type="text" name="birth" value="2021-10-22"/><br>
  Tel1:<input type="text" name="tel" value="123235252532"/><br>
  Tel2:<input type="text" name="tel" value="161242435332"/><br>
  IdCard:<input type="text" name="card.cardNum" value="354636235623647425"/><br>
  Address1:<input type="text" name="addresses[0].addr" value="广州"/><br>
  Address2:<input type="text" name="addresses[1].addr" value="珠海"/><br>
  <input type="submit" value="提交">
</form>
</body>
</html>

第六:创建一个jsp,接收信息

webapp/WEB-INF/jsp/index.jsp

<%--
  Created by IntelliJ IDEA.
  User: hy
  Date: 2023/10/20
  Time: 10:00
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h2>这是首页</h2>
用户名:${requestScope.username}<br>
年龄:${requestScope.age}<br>
生日:${requestScope.birth}<br>
电话1:${requestScope.tel1}<br>
电话2:${requestScope.tel2}<br>
住址1:${requestScope.addr1}<br>
住址2:${requestScope.addr2}<br>
身份证:${requestScope.idCard}<br>
路径参数:${requestScope.uid}<br>
</body>
</html>

第七:编写实体类

用户表

@Data
public class User {
    private String username;
    private Integer age;
    private Date birth;
    private List<String> tel;
    // 一对一关联身份证
    private IdCard card;
    // 一对多关联地址
    private List<Address> addresses;
}

身份证表

@Data
public class IdCard {
    private String cardNum;
}

地址表

@Data
public class Address {
    private String addr;
}

第八:编写controller层

1. 参数请求方法一

基本类型和String类型作为参数

package edu.nf.ch04.controller;

import edu.nf.ch04.entity.User;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @Date 2023-10-20
 * @Author hy
 */
@Controller
@Slf4j
public class UserController {

    @PostMapping("/add")
    public ModelAndView add(HttpServletRequest request){
        String username = request.getParameter("username");
        String age = request.getParameter("age");
        log.info(username,age);
        // 将参数放入请求作用域
        //request.setAttribute("username",username);
        //request.setAttribute("age",age);

        ModelAndView mav = new ModelAndView("index");
        mav.addObject("username",username);
        mav.addObject("age",age);
        return mav;
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 参数请求方法二

Date类型 和 数组类型 作为参数

package edu.nf.ch04.controller;

import edu.nf.ch04.entity.User;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @Date 2023-10-20
 * @Author hy
 */
@Controller
@Slf4j
public class UserController {
      /**
     * 注册自定义转换器,@InitBinder注解标注的方法会在执行
     * 任何Controller的方法之前先执行,springmvc会传入
     * 一个WebBinder的参数,使用这个参数可以注册任意的Formatter(格式化器)
     *
     *  @param binder 数据绑定器,用于注册各种格式化类
     */
    @InitBinder
    public void regFormatter(WebDataBinder binder){
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    };
   
    /**
     * 将请求数据直接绑定到参数上,
     * 默认参数名与请求中的name保持一致即可映射,
     * 否则使用@RequestParam注解来绑定参数名
     * @param userName
     * @param userAge
     * @return
     */
    @PostMapping("/add2")
    public ModelAndView add2(@RequestParam("username") String userName,
                             @RequestParam("age") Integer userAge,
                             Date birth,
                             String[] tel){
        ModelAndView mav = new ModelAndView("index");
        // 将参数保存到请求作用域
        mav.addObject("username",userName);
        mav.addObject("age",userAge);
        mav.addObject("birth",birth);
        mav.addObject("tel1",tel[0]);
        mav.addObject("tel2",tel[1]);
        return mav;

    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3. 参数请求方法三

实体对象(包含集合类型) 作为参数

package edu.nf.ch04.controller;

import edu.nf.ch04.entity.User;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @Date 2023-10-20
 * @Author hy
 */
@Controller
@Slf4j
public class UserController {
      /**
     * 注册自定义转换器,@InitBinder注解标注的方法会在执行
     * 任何Controller的方法之前先执行,springmvc会传入
     * 一个WebBinder的参数,使用这个参数可以注册任意的Formatter(格式化器)
     *
     *  @param binder 数据绑定器,用于注册各种格式化类
     */
    @InitBinder
    public void regFormatter(WebDataBinder binder){
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    };

    @PostMapping("/add3")
    public ModelAndView add3(User user){
        ModelAndView mav = new ModelAndView("index");
        // 将参数保存到请求作用域
        mav.addObject("username",user.getUsername());
        mav.addObject("age",user.getAge());
        mav.addObject("birth",user.getBirth());
        mav.addObject("tel1",user.getTel().get(0));
        mav.addObject("tel2",user.getTel().get(1));
        mav.addObject("idCard",user.getCard().getCardNum());
        mav.addObject("addr1",user.getAddresses().get(0).getAddr());
        mav.addObject("addr2",user.getAddresses().get(1).getAddr());
        return mav;
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4. 路径参数请求

自定义路径参数

package edu.nf.ch04.controller;

import edu.nf.ch04.entity.User;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @Date 2023-10-20
 * @Author hy
 */
@Controller
@Slf4j
public class UserController {

    /**
     * 路径参数绑定
     * 请求格式:/url地址/{变量},
     * 并且使用@PathVariable注解来映射
     *
     * @param uid
     * @return
     */
    @GetMapping("/user/{id}")
    public ModelAndView getUser(@PathVariable("id") String uid){
        ModelAndView mav = new ModelAndView("index");
        mav.addObject("uid",uid);
        return mav;
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

八、SpringMVC的注解

1、@InitBinder

  • 标注的方法会在执行任何Controller的方法之前先执行
    /**
     * 注册自定义转换器,@InitBinder注解标注的方法会在执行任何Controller的方法之前先执行,
     * springmvc会传入一个WebDataBinder的参数,使用这个参数可以注册任意的Formatter(格式化器)
     *
     * @param binder 数据绑定器,用于注册各种格式化类
     */
    @InitBinder
    public void regFormatter(WebDataBinder binder){
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    };

2、@RequestParam

  • 当默认参数名与请求中的name不一致时,使用@RequestParam注解来绑定参数名

例如:下面示例中,请求的name是userName和userAge,而默认参数名是username和age

  /**
     * 将请求数据直接绑定到参数上,
     * 默认参数名与请求中的name保持一致即可映射,
     * 否则使用@RequestParam注解来绑定参数名
     * @param userName
     * @param userAge
     * @return
     */
    @PostMapping("/add2")
    public ModelAndView add2(@RequestParam("username") String userName,
                             @RequestParam("age") Integer userAge,
                             Date birth,
                             String[] tel){
        ModelAndView mav = new ModelAndView("index");
        // 将参数保存到请求作用域
        mav.addObject("username",userName);
        mav.addObject("age",userAge);
        mav.addObject("birth",birth);
        mav.addObject("tel1",tel[0]);
        mav.addObject("tel2",tel[1]);
        return mav;

    }

3、@PathVariable

  • 映射路径参数
    /**
     * 路径参数绑定
     * 请求格式:/url地址/{变量},
     * 并且使用@PathVariable注解来映射
     *
     * @param uid
     * @return
     */
    @GetMapping("/user/{id}")
    public ModelAndView getUser(@PathVariable("id") String uid){
        ModelAndView mav = new ModelAndView("index");
        mav.addObject("uid",uid);
        return mav;
    }

4、@ResponseBody

  • 使用@ResponseBody注解,表示将方法返回值 以输出流的方式写回客户端
  • 或者在类上直接使用@RestController,相当于当前类中所有的请求方法 都使用@ResponseBody注解

简单的说,就是将java对象(实体对象)转为json请求体格式的数据,也称之为序列化,响应给浏览器

如下案例:将User对象序列化为JSON数据{“username”:“simi”}

@Controller
@Slf4j
public class UserController {
    @GetMapping("/user")
    /**
     * 使用@ResponsseBody注解,表示将方法返回值以输出流的方式写回客户端,
     * 这样springmvc就会将序列化好的json数据放入响应体中并写回
     */
    @ResponseBody
    public User getUser(){
        User user = new User();
        user.setUsername("simi");
        return user;
    }
}

注意:添加依赖

  <!-- 如果使用了JSON作为响应数据,需要依赖Jackson包,
        它是spring官方默认集成的JSON序列化工具 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.1</version>
        </dependency>
    </dependencies>

九、视图响应注解

1、@RequestBody

  • 当前端提交的是一个json字符串时,使用@RequestBody注解映射,springmvc就会将json字符串反序列化为实体对象。

简单的说,它是用来接收 前端传递给后端 的json字符串中的数据(请求体中的数据),

就是将前端的json格式的数据转为java对象(实体对象),也称之为反序列化,传入后台

请求体中的数据要传入后台,后台要用@RequestBody才能接收到

 /**
     * 当前端提交的是一个json字符串时,
     * 此时要使用@RequestBody注解来映射,
     * 这样springmvc就会将json字符串反序列化为实体对象
     * @param user
     * @return
     */
    @PostMapping("/add")
    public String add(@RequestBody User user){
        log.info(user.getUsername());
        return "success";
    }

客户端(浏览器)向服务器发送请求(输入url地址),服务器接收请求并返回响应

2、转发

2.1 通过ModelAndView对象转发视图
package edu.nf.ch06.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class TestController {
    /**
     * 转发视图
     * @return
     */
    @GetMapping("/forward1")
    public ModelAndView forward1(){
       return new ModelAndView("index");
    }
}
2.2 返回String类型,转发视图
package edu.nf.ch06.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
@Slf4j
public class TestController {
    /**
     * 转发视图2
     * @return
     */
    @GetMapping("/forward2")
    public String forward2(){
        log.info("转发视图");
        return "index";
    }
}
2.3 转发请求url,必须使用"forward:"前缀
package edu.nf.ch06.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;


@Controller
@Slf4j
public class TestController {
  
    /**
     * 转发视图2
     * @return
     */
    @GetMapping("/forward2")
    public String forward2(){
        log.info("转发视图");
        return "index";
    }
  
    /**
     * 转发请求url,必须使用"forward:"前缀
     * 注意:转发视图是通过InternalResourceViewResolver解析器来完成的。
     * 而转发请求的url是一个地址,并非视图,因此需要加上forward:前缀,并且url的路径必须写完整
     * @return
     */
    @GetMapping("/forward3")
    public String forward3(){
        return "forward:forward2";
    }
}

3、重定向

重定向一个视图或者请求地址,结合“redirect:"这个前缀
package edu.nf.ch06.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * @Date 2023-10-23
 * @Author hy
 */
@Controller
@Slf4j
public class TestController {

    /**
     * 如果需要重定向一个视图或者请求地址
     * 可以结合“redirect:"这个前缀,
     * 并且重定向的地址和视图名称必须是完整的url路径。
     * 因为重定向是不会走内部资源视图解析器的
     * @return
     */
    @GetMapping("/redirect1")
    public String redirect1(Model model){
        model.addAttribute("name","simi");

        // 重定向传递信息的方法
        // 1.会话作用域
        // 2.Url的重写
        // 这里的参数是从地址栏里添加,不通过请求作用域,是额外的
        // "redirect:redirect.jsp?name=simi"
        return "redirect:redirect.jsp";
    }

    /**
     * RedirectAttributes是springmvc3.1版本提供的一个类
     * 主要用于在重定向时可以重写url,在重定向的url后面加入参数,
     * 这样就可以变相在重定向的资源中获取相关的参数信息
     * @param redirectAttributes
     * @return
     */
    @GetMapping("/redirect2")
    public String redirect2(RedirectAttributes redirectAttributes){
        redirectAttributes.addAttribute("name","simi");
        // 相当于"redirect:redirect.jsp?name=simi"
        return "redirect:redirect.jsp?";
    }

}

十、表单验证

@NotEmpty注解

1. 添加依赖

   <dependencies>
        <!-- 如果使用了JSON作为响应的数据,需要依赖Jackson包
             它是springmvc官方默认集成的JSON序列化工具 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.1</version>
        </dependency>

        <!-- 集成hibernate bean验证器 -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.13.final</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
    </dependencies>

2. 配置核心请求总控器

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 配置核心请求总控器,负责接收所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

3. 编写错误验证提示

在resources目录下,配置message.properties文件

user.userName.notEmpty = 请输入用户名
user.age.notNull = 请输入年龄
user.age.min = 年龄不得小于18岁
user.birth.notNull = 请输入出生年月
user.email.notEmpty = 请输入邮箱地址
user.email.legal = 请填写合法Email地址

4. 配置校验器

WEB-INF目录下,配置dispatcher-servlet.xml

查找到message.properties验证文件的路径,配置校验器(一起)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 扫描 -->
    <context:component-scan base-package="edu.nf.ch07"/>

    <!-- 启用mvc注解驱动,注意:需要重新引用验证的id -->
    <mvc:annotation-driven validator="validator"/>

    <!-- 默认servlet处理静态资源处理 -->
    <mvc:default-servlet-handler/>


    <!--配置资源消息-->
    <!-- 查找到message.properties验证文件的路径 -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!--配置资源文件的路径-->
        <property name="basenames">
            <list>
                <!--指定资源文件的位置,注意:不需要写文件的后缀-->
                <value>classpath:message</value>
            </list>
        </property>
        <!-- 指定编码格式 -->
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

    <!-- 配置校验器 -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!--注入校验器的提供方,-->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
        <!-- 引入资源文件 -->
        <property name="validationMessageSource" ref="messageSource"/>
    </bean>


</beans>

5. 校验数据

编写Controller层方法

package edu.nf.ch07.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.nf.ch07.controller.vo.ResultVo;
import edu.nf.ch07.entity.User;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

/**
 * @Date 2023-10-24
 * @Author hy
 */
@RestController
public class UserController {
    /**
     * 注册日期格式化器
     * @param binder
     */
    @InitBinder
    public void regFormatter(WebDataBinder binder){
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }


    /**
     * @Valid注解标注的参数实体要参与Bean验证
     *
     * 从前端传递过来的data数据,进入User对象进行验证,
     * 再通过BindingResult对象返回验证结果(在实体类验证时就自动生成该对象,这里只是回调使用)
     */
    @PostMapping("/add")
    public ResultVo add(@Valid User user, BindingResult result) throws JsonProcessingException {
          ResultVo vo = new ResultVo();
          // 先判断是否校验通过,如果存在错误则表示未通过
          if(result.hasErrors()){
              Map<String,String> errors = new HashMap<>();
              result.getFieldErrors().forEach(fieldError ->{
                  // 以字段名作为key,错误信息作为value保存到map中
                  errors.put(fieldError.getField(),fieldError.getDefaultMessage());
              });
              // 设置响应状态码 - 500
              vo.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
              // 将map序列化为json字符串
              String messages = new ObjectMapper().writeValueAsString(errors);
              vo.setMessage(messages);

              // 直接将errors保存到data中
              //vo.setData(map);
              return vo;
          }
          return vo;
    }
}

6. 实体对象信息

package edu.nf.ch07.entity;

import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.Email;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;

/**
 * @Date 2023-10-24
 * @Author hy
 */
@Data
public class User {
    /**
     * 验证空串
     */
    // 方法一:直接输入验证错误信息
    //@NotEmpty(message = "请输入用户名")
    // 方法二:调用message.properties文件
    @NotEmpty(message = "{user.userName.notEmpty}")
    private String userName;
    /**
     * 验证空值
     */
    @NotNull(message = "{user.age.notNull}")
    /**
     * 最小值范围
     */
    @Min(value = 18,message = "{user.age.min}")
    private Integer age;

    @NotNull(message = "{user.birth.notNull}")
    // 不推荐,只能定义一种,在实际开发中不可取
    // @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;

    @NotEmpty(message = "{user.email.notEmpty}")
    @Email(message = "{user.email.legal}")
    private String email;
}

7. 注册页面-验证信息

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/jquery-1.12.4.js"></script>
</head>
<body>
<h2>用户注册</h2>
<!-- 这个div用来显示验证的信息 -->
<div id="msg" style="color:red;"></div>
<form id="f1">
  Name:<input type="text" name="userName"/><br>
  Age:<input type="text" name="age"/><br>
  Birth:<input type="text" name="birth"/><br>
  Email:<input type="text" name="email"/><br>
  <input type="button" value="注册"/>
</form>
<script>
    $(function (){
        $(':button').on('click',function (){
            $.ajax({
                url:'../add',
                type:'post',

                // 请求体格式:username=simi&age=12
                // json字符串:{"username":"simi","age":"12"}
                // json对象[object Object],可以打开

                /**
                 * 序列化表单数据,这里数据是以请求体格式(username=zs&age=20...)传递的,
                 * 如果我们提交的不是规范的请求体格式而是一个json字符串{‘userName’:'zs','age':20...},
                 * 那么我们后端就需要使用@RequestBody注解来映射,这样springmvc就会将json字符串反序列化为实体对象。
                 */
                data:$('#f1').serialize(),
                success:function (result){
                    if(result.code == 500){
                        $('#msg').empty();
                        let errors = result.message;
                        //将json字符串转换为json对象
                        errors = $.parseJSON(errors);
                        // 循环遍历错误信息放在div中
                        $.each(errors,function (key,val){
                            $('#msg').append(val + '<br>')
                        });
                    }else if(result.code == 200){
                        alert("注册成功")
                    }
                }
            })
        })
    })
</script>
</body>
</html>

十一、附件上传

上传过程:打开文件夹,上传到指定路径

1. 添加依赖

  <!-- 上传组件 -->
  <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
  </dependency>

2. 配置核心请求总控器

编写web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置核心请求总控器,负责接收所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

3. 装配上传附件解析器

编写dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 扫描 -->
    <context:component-scan base-package="edu.nf.ch08"/>

    <!-- 启用mvc注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 默认servlet处理静态资源处理 -->
    <mvc:default-servlet-handler/>

    <!-- 装配上传附件解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 限制文件上传的总大小(单位:字节),不配置此属性默认不限制 -->
        <property name="maxUploadSize" value="104857600"/>
        <!-- 设置文件上传的默认编码-->
        <property name="defaultEncoding" value="utf-8"/>
    </bean>

</beans>

4. 保存页面提交的数据

编写ProductVO,相当于实体类

package edu.nf.ch08.controller.vo;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

/**
 * 商品vo对象,用于保存页面提交的数据
 * 后续将这个vo拷贝到entity中
 * @Date 2023-10-24
 * @Author hy
 */
@Data
public class ProductVO {
    /**
     * 商品名称
     */
    private String productName;

    /**
     * MultipartFile是springmvc封装的上传附件对象
     * 商品图片
     */
    private MultipartFile[] file;
}

5. 封装结果集

package edu.nf.ch08.controller.vo;

import lombok.Data;
import org.springframework.http.HttpStatus;

/**
 * 返回结果集
 * @Date 2023-10-24
 * @Author hy
 */
@Data
public class ResultVO <T>{
    // 设置默认值为200
    private Integer code = HttpStatus.OK.value();
    private String message;
    private T data;
}

6. 上传附件

编写Controller层方法

package edu.nf.ch08.controller;

import ch.qos.logback.core.FileAppender;
import edu.nf.ch08.controller.vo.ProductVO;
import edu.nf.ch08.controller.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
 * @Date 2023-10-24
 * @Author hy
 */
@Slf4j
@RestController
public class ProductController {
    /**
     * 添加商品,同时带有上传的附件
     * @param productVO
     * @return
     */
    @PostMapping("/add")
    public ResultVO add(ProductVO productVO) throws IOException {
        ResultVO vo = new ResultVO();
        // 获取上传的路径 (绝对路径)
        String uploadPath = "D://springmvc/files/";
        log.info(uploadPath);

        // 根据路径构建上传的文件对象
        File uploadFile = new File(uploadPath);
        // 判断路径创建出的文件夹是否存在,不存在则创建出来
        if(!uploadFile.exists()){
            // 将文件夹创建出来
            uploadFile.mkdirs();
        }

        // 获取所有上传的附件
        // 上传单条
        //MultipartFile file = productVO.getFile();
        // 上传多条
        MultipartFile[] files = productVO.getFile();

        // 循环遍历
        for(MultipartFile file :files){
            // 获取文件名
            String filName = file.getOriginalFilename();
            // 执行上传
            Path path = FileSystems.getDefault().getPath(uploadFile.getAbsolutePath(),filName);
            // 执行IO的读写
            file.transferTo(path);
        }

        return vo;
    }
}

7. 添加附件的页面

前端提交商品信息,multiple表示多选

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/jquery-1.12.4.js"></script>
</head>
<body>
<h1>添加商品</h1>
<form id="f1" enctype="multipart/form-data">
  Name:<input type="text" name="productName"/><br>
  Image:<input type="file" name="file" multiple/><br>
    <input type="button" value="提交"/>
</form>
<script>
    $(function (){
        $(':button').on('click',function (){
            // 构建formData对象
            // formData对象是 Html5的内置对象,同样是处理from表单的数据
            // 但formData对象可以处理文本和二进制数据,而序列化只能在文本有效
            // 这里包含附件,所以使用formData对象
            let formData = new FormData($('#f1')[0]);
            $.ajax({
                url: '../add',
                type: 'post',
                data: formData,
                // 设置属性为false,就是使formData对象正常使用,而不会回到序列化的请求格式
                processData: false, // 告诉jquery不要处理发送的数据类型
                contentType: false, // 告诉jquery不要设置请求头的content-Type
                success: function (result){
                    if(result.code == 200){
                        alert('上传成功');
                    }
                }
            })
        })
    })
</script>
</body>
</html>

十二、本地下载

下载过程:idea的控制层指定下载文件的路径,通过浏览器,下载到浏览器默认下载路径

本地下载

编写Controller层方法,这里使用的是路径参数

也可以在浏览器里输入http://localhost:8080/download?fileName=''指定文件名"

package edu.nf.ch08.controller;

import edu.nf.ch08.controller.vo.ProductVO;
import edu.nf.ch08.controller.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
 * @Date 2023-10-24
 * @Author hy
 */
@Slf4j
@RestController
public class ProductController {

    /**
     * 下载
     * @param fileName
     * @return
     * @throws FileNotFoundException
     * @throws UnsupportedEncodingException
     */
    @GetMapping("/download/{fileName}")
    public ResponseEntity<InputStreamResource> download(@PathVariable("fileName") String fileName) throws FileNotFoundException, UnsupportedEncodingException {
        // 文件下载路径(也是上传路径), 注意:文件夹不存在文件,需先上传再下载
        String downloadPath = "D://springmvc/files/" + fileName;
        // 构建一个文件输入流读取服务器上的文件
        FileInputStream fis = new FileInputStream(downloadPath);
        // 设置响应头,告诉浏览器响应流数据
        HttpHeaders headers = new HttpHeaders();
        // 对文件名进行编码,防止在响应头中出现乱码
        fileName = URLEncoder.encode(fileName,"UTF-8");
        // 设置头信息,将响应内容处理的方式设置为附件下载
        headers.setContentDispositionFormData("attachment", fileName);
        // 设置响应类型为流类型
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // 创建InputStreamResource对象封装输入流,用于读取服务器文件
        InputStreamResource isr = new InputStreamResource(fis);
        // 创建ResponseEntity对象(封装InputStreamResource、响应头、响应状态码)
        ResponseEntity<InputStreamResource> entity = new ResponseEntity<>(isr,headers, HttpStatus.CREATED);
        return entity;
    }
}

十三、minio的应用

1. 远程桶

1.1 下载minio

minio下载

1.2 cmd命令启动minio

打开含有minio.exe的文件夹,输入cmd,打开命令符

输入:minio.exe server D:\minio\data --console-address “:9001” (D:\minio\data:minio的下载路径)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3 浏览器打开远程minio

通过cmd命令启动后,才能在浏览器中打开

输入网址:http://127.0.0.1:9001/,密码跟账户一致

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.4 设置文件访问权限

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.5 访问文件

输入文件路径:http://127.0.0.1:9000/myapp/images/cb.jpg

2. idea创建桶

第一:添加依赖
   <!-- minio客户端-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.4</version>
        </dependency>
第二:创建桶

编写MinioUtils工具类

package edu.nf.minio.util;

import io.minio.*;
import java.io.IOException;

public class MinioUtils {
    //minioClient:minio服务器的客户端
    private static MinioClient minioClient;

    static {
        // 创建minioClient
        minioClient = MinioClient.builder()
               // 文件访问路径
                .endpoint("http://127.0.0.1:9000")
                // 账户密码
                .credentials("minioadmin","minioadmin")
                .build();
    }

    /**
     * 创建桶
     * 每个桶之间都是隔离的
     * @param bucketName
     */
    public static void createBucket(String bucketName) throws Exception{
        // 先判断桶是否存在,不存在则创建
        if(!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())){
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }
}
第三:实现
package edu.nf;

import edu.nf.minio.util.MinioUtils;
import io.minio.MinioClient;


public class Main {
    public static void main(String[] args) throws Exception {
        // 创建桶
        MinioUtils.createBucket("myapp");
    }
}

3. 上传

上传前先启动远程桶

先将文件上传到本地,再将本地文件上传到远程minio,两次读写

package edu.nf.minio.util;

import io.minio.*;

public class MinioUtils {
    private static MinioClient minioClient;
  
    static {
        // 创建minioClient
        minioClient = MinioClient.builder()
                .endpoint("http://127.0.0.1:9000")
                .credentials("minioadmin","minioadmin")
                .build();
    }

    /**
     * 上传桶
     * @param bucketName 桶的名称
     * @param remotePath 远程要上传文件路径
     * @param localPath 本地文件路径
     */
    public static void upload(String bucketName,String remotePath,String localPath) throws Exception {
        minioClient.uploadObject(UploadObjectArgs.builder().
                // 指定桶的名字
                bucket(bucketName)
                // 上传的远程文件路径
                .object(remotePath)
                // 本地文件的路径
                .filename(localPath)
                .build());
    }
}

实现

public class Main {
    public static void main(String[] args) throws Exception {
        // 上传
        String bucket = "myapp";
        String remotePath = "images/cb.jpg";
        String localPath = "D://springmvc/files/cb.jpg";
        MinioUtils.upload(bucket,remotePath,localPath);
    }
}

4. 下载

下载前先启动远程桶

将远程minio文件,下载到本地

package edu.nf.minio.util;

import io.minio.*;
import java.io.IOException;


public class MinioUtils {
    private static MinioClient minioClient;

    static {
        // 创建minioClient
        minioClient = MinioClient.builder()
                .endpoint("http://127.0.0.1:9000")
                .credentials("minioadmin","minioadmin")
                .build();
    }

    /**
     * 下载文件
     *
     * @param bucketName 桶的名称
     * @param remotePath 远程文件路径
     * @param downloadPath 下载到本地保存的路径
     */
   public static void download(String bucketName, String remotePath, String downloadPath) throws Exception {
        minioClient.downloadObject(DownloadObjectArgs.builder()
                // 指定桶的名字
                .bucket(bucketName)
                // 远程文件路径
                .object(remotePath)
                // 下载到本地保存的路径
                .filename(downloadPath)
                .build());
   }
}

实现

将远程minio的文件,下载到桌面

public class Main {
    public static void main(String[] args) throws Exception {
        // 下载
        String bucket = "myapp";
        String remotePath = "images/cb.jpg";
        String localPath = "C://Users/hy/Desktop/cb.jpg";
        MinioUtils.download(bucket,remotePath,localPath);
    }
}

十四、异常处理

1、配置 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置核心请求总控器,负责接收所有的请求,并根据映射的url地址将请求分发给具体控制器的方法来处理 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

2、配置 dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 扫描 -->
    <context:component-scan base-package="edu.nf.ch09"/>
    <!-- 启用mvc注解驱动 -->
    <mvc:annotation-driven/>
    <!-- 默认servlet处理静态资源处理 -->
    <mvc:default-servlet-handler/>
</beans>

3、封装结果集

package edu.nf.ch09.controller.vo;

import lombok.Data;
import org.springframework.http.HttpStatus;

/**
 * @Date 2023-10-27
 * @Author hy
 */
@Data
public class ResultVO<T> {
    private Integer  code = HttpStatus.OK.value();
    private String message;
    private T data;
}

4、自定义异常

package edu.nf.ch09.exception;

/**
 * 自定义异常
 * @Date 2023-10-27
 * @Author hy
 */
public class AuthException extends RuntimeException{
    /**
     * 异常的状态码
     */
    private Integer errorCode;

    public AuthException(Integer errorCode,String message){
        super(message);
        this.errorCode = errorCode;
    }

    /**
     * 提供一个获取错误码的方法
     * @return
     */
    public Integer getErrorCode(){
        return errorCode;
    }
}

5、dao实现

package edu.nf.ch09.dao.impl;

import edu.nf.ch09.dao.UserDao;
import edu.nf.ch09.entity.User;
import org.springframework.stereotype.Repository;

/**
 * @Date 2023-10-27
 * @Author hy
 */
@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public User getUser(String username) {
        User user = new User();
        user.setUsername(username);
        user.setPassword("123456");
        return user;
    }
}

6、service实现类

package edu.nf.ch09.service.impl;

import edu.nf.ch09.dao.UserDao;
import edu.nf.ch09.entity.User;
import edu.nf.ch09.exception.AuthException;
import edu.nf.ch09.service.LoginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @Date 2023-10-27
 * @Author hy
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {

    private final UserDao userDao;
    @Override
    public User auth(String username, String password) {
        User user = userDao.getUser(username);
        // 用户不为null则校验密码
        if(user != null){
            if(password.equals(user.getPassword())){
                return user;
            }
        }
        // 抛出业务异常
        throw new AuthException(1000,"账户或密码错误");
    }
}

7、局部异常

package edu.nf.ch09.controller;

import edu.nf.ch09.controller.vo.ResultVO;
import edu.nf.ch09.entity.User;
import edu.nf.ch09.service.LoginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

/**
 * @Date 2023-10-27
 * @Author hy
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class UserController {
    private final LoginService service;

    /**
     * 局部异常处理(处理登录业务异常)
     * @ExceptionHandler注解标注的方法专门用于处理请求方法产生的异常
     * value属性指定要处理的异常类型
     * 注意:这个局部异常只在当前的Controller中有效,也就是说
     * 每个controller都有自己专门的handlerException的方法
     * @param e
     * @return
     */
//    @ExceptionHandler({AuthException.class})
//    public ResultVO handleAuthException(AuthException e){
//        //验证未通过则创建提示信息
//        ResultVO vo = new ResultVO();
//        vo.setCode(e.getErrorCode());
//        vo.setMessage(e.getMessage());
//        return vo;
//    }

    /**
     * 局部异常处理(处理非业务异常,如数据库异常等)
     * @param
     * @return
     */
//    @ExceptionHandler({RuntimeException.class})
//    public ResultVO handleRunTimeException(RuntimeException e){
//        // 记录异常日志
//        log.error(e.getMessage());
//        // 再将异常转换为提示信息
//        ResultVO vo = new ResultVO();
//        vo.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
//        vo.setMessage("服务器内部错误,请稍后尝试");
//        return vo;
//    }

    @PostMapping("/login")
    public ResultVO login(String username, String password, HttpSession session){
            User user = service.auth(username, password);
            log.info(user.getPassword(),user.getPassword());
            // 将用户保存到会话
            session.setAttribute("user", user);
            return new ResultVO();
    }
}

8、全局异常

package edu.nf.ch09.controller.advice;

import edu.nf.ch09.controller.vo.ResultVO;
import edu.nf.ch09.exception.AuthException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 定义一个全局异常处理类(类似一个切面)
 * 这个类中定义所有的异常处理方法,也可以
 * 理解为全局异常通知
 * @Date 2023-10-27
 * @Author hy
 */
// @RestControllerAdvice(对应@Controller注解的类)
    // (对应@ResutController注解的类)
// value属性表示:controller包下的所有类都参与异常捕获
@RestControllerAdvice("edu.nf.ch09.controller")
@Slf4j
public class ExceptionAdvice {
    /**
     * 全局异常处理方法(处理登录业务异常)
     * @param e
     * @return
     */
    @ExceptionHandler({AuthException.class})
    public ResultVO handleAuthException(AuthException e){
        //验证未通过则创建提示信息
        ResultVO vo = new ResultVO();
        vo.setCode(e.getErrorCode());
        vo.setMessage(e.getMessage());
        return vo;
    }

    /**
     * 全局异常处理方法(处理非业务异常,如数据库异常等)
     * @param e
     * @return
     */
    @ExceptionHandler({Exception.class})
    public ResultVO handleRunTimeException(Exception e){
        // 记录异常日志
        log.error(e.getMessage());
        // 再将异常转换为提示信息
        ResultVO vo = new ResultVO();
        vo.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
        vo.setMessage("服务器内部错误,请稍后尝试");
        return vo;
    }

}

9、页面实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <script src="js/jquery-1.12.4.js"></script>
</head>
<body>
<h1>用户登录</h1>
<form id="f1">
    账户:<input type="text" name="username"/><br>
    密码:<input type="password" name="password"/><br>
    <input type="button" value="登录"/>
</form>
<script>
    $(function (){
        $(':button').on('click',function (){
            let formData = $('#f1').serialize();
            $.ajax({
                url:'../login',
                type:'post',
                data: formData,
                success:function (result){
                    console.info(result)
                    if(result.code == 200){
                        // 跳转到首页
                        location.href = 'index.html';
                    }else if(result.code == 1000){
                        alert(result.message);
                    }
                }
            })
        })
    })
</script>
</body>
</html>

十五、拦截器

1、配置web.xml

2、封装结果集

3、配置拦截器栈

配置dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 扫描 -->
    <context:component-scan base-package="edu.nf.ch10"/>
    <!-- 启用mvc注解驱动 -->
    <mvc:annotation-driven/>
    <!-- 默认servlet处理静态资源处理 -->
    <mvc:default-servlet-handler/>

    <!-- 配置拦截器栈 -->
    <mvc:interceptors>
        <!-- 配置具体的拦截器 -->
        <mvc:interceptor>
            <!-- 设置哪些请求会经过这个拦截器 -->
            <mvc:mapping path="/**"/>
            <!-- 排除哪些请求不经过这个拦截器 -->
            <mvc:exclude-mapping path="/static/login.html"/>
            <mvc:exclude-mapping path="/auth"/>
            <mvc:exclude-mapping path="/static/js/**"/>
            <!-- 装配具体的拦截器 -->
            <bean class="edu.nf.ch10.interceptor.AuthInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

4、service实现

package edu.nf.ch10.service.impl;

import edu.nf.ch10.entity.User;
import edu.nf.ch10.service.LoginService;
import org.springframework.stereotype.Service;

/**
 * @Date 2023-10-27
 * @Author hy
 */
@Service
public class LoginServiceImpl implements LoginService {
    /**
     * 登录验证
     * @param username
     * @param password
     * @return
     */
    @Override
    public User auth(String username, String password) {
        if("simi".equals(username) && "123456".equals(password)){
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            return user;
        }
        throw new RuntimeException("账户或密码错误");
    }
}

5、controller实现

package edu.nf.ch10.controller;

import edu.nf.ch10.controller.vo.ResultVO;
import edu.nf.ch10.entity.User;
import edu.nf.ch10.service.LoginService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;

/**
 * @Date 2023-10-27
 * @Author hy
 */
@RestController
@RequiredArgsConstructor
public class UserController {
    private final LoginService service;

    @PostMapping("/auth")
    public ResultVO login(String username, String password, HttpSession session){
        User user = service.auth(username,password);
        session.setAttribute("user",user);
        return new ResultVO();
    }
}

6、拦截器

package edu.nf.ch10.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.nf.ch10.controller.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 认证拦截器
 * 拦截所有的请求,如果为登录则返回401状态码
 * 401:未认证,用户未登录
 * 403:没有权限,用户没有相关权限
 * @Date 2023-10-27
 * @Author hy
 */
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
    /**
     * 在调用Controller请求方法之前执行,
     * 如果此方法返回false,则请求就不会继续往下执行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      log.info("执行preHandle方法");
        HttpSession session = request.getSession();
        // 如果session为null表示用户未登录
        if(session.getAttribute("user") == null){
            ResultVO vo = new ResultVO();
            // 设置401状态码
            vo.setCode(HttpStatus.UNAUTHORIZED.value());
            vo.setMessage("未登录");
            response.setContentType("application/json;charset=utf-8");
            String json = new ObjectMapper().writeValueAsString(vo);
            response.getWriter().println(json);
            return false;
        }
      return true;
    }

    /**
     * 在调用Controller方法之后,返回之前执行(也就是说,开始了controller的方法,但是还没有执行return操作时,调用此方法)
     * (注意:只有在preHandle方法返回true的情况下才会执行)
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("执行postHandle方法");
    }

    /**
     * 调用Controller方法并返回后执行(也就是说,已经执行完return操作,才调用此方法)
     * (注意:只有在preHandle方法返回true的情况下才会执行)
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

7、页面实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <script src="js/jquery-1.12.4.js"></script>
</head>
<body>
<h1>用户登录</h1>
<form id="f1">
  账户:<input type="text" name="username"/><br>
  密码:<input type="password" name="password"/><br>
  <input type="button" value="登录"/>
</form>
<script>
  $(function (){
    $(':button').on('click',function (){
      let formData = $('#f1').serialize();
      $.ajax({
        url:'../auth',
        type:'post',
        data: formData,
        success:function (result){
          if(result.code == 200){
            location.href = 'index.html';
          }
        }
      })
    })
  })
</script>
</body>
</html>

十六、零XML配置

用配置类取代xml配置

在使用Spring MVC时,每次都要去配置web.xml、spring-mvc.xml,甚至和Spring整合时候,还要配置spring.xml,用起来比较麻烦。而Spring Boot中使用Spring MVC时就不会去指定xml,这是因为Spring Boot提供了一种零XML配置的方式。

具体实现方式如下:
通过注解@EnableWebMvc启用Spring MVC;
通过@Configuration注解定义一个配置类,并实现WebMvcConfigurer接口;
在配置类中重写addResourceHandlers方法,添加静态资源路径;
在配置类中重写addViewControllers方法,添加视图控制器;
在配置类中重写configureDefaultServletHandling方法,开启默认Servlet处理;
在配置类中重写configureViewResolvers方法,配置视图解析器。
通过以上步骤,就可以实现Spring MVC的零XML配置。这种方式可以减少配置文件的数量,提高开发效率,同时也更加符合现代化的开发理念。

配置类一:JDBC

package edu.nf.ch12.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.io.InputStream;
import java.util.Properties;

/**
 * JDBC配置
 * @Date 2023-10-30
 * @Author hy
 */
@Configuration
// 启用事务注解驱动,这样就可以在业务类中使用@Transaction注解
@EnableTransactionManagement
public class JdbcConfig {

    /**
     * 整合druid数据源连接池,装配DruidDataSource
     * @return
     */
    @Bean(initMethod = "init",destroyMethod = "close")
    public DruidDataSource dataSource() throws Exception {
        // 创建Properties对象
        Properties prop = new Properties();
        // 获取一个输入流来读取properties文件
        InputStream input = SpringConfig.class.getClassLoader()
                .getResourceAsStream("jdbc.properties");
        // 将输入流加载到properties读写中
        prop.load(input);
        // 通过DruidDataSourceFactory来创建DruidDataSource实例
        DruidDataSource ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);

        return ds;
    }

    /**
     * 装配事务管理器,并注入数据源,
     * 这样事务管理器就可以基于AOP来管理Connection的事务操作
     * @param dataSource
     * @return
     */
    @Bean
    public PlatformTransactionManager txManager(DruidDataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

配置类二:springmvc

package edu.nf.ch12.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * springmvc配置类,
 * 用于取代dispatcher-servlet.xml
 * @Date 2023-10-30
 * @Author hy
 */
// 声明配置类
@Configuration
// 启动mvc注解驱动
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    /**
     * 静态资源处理
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        //enable()方法表示使用容器默认servlet处理
        configurer.enable();
    }

    /**
     * 配置内部资源视图解析器(内部资源视图的转发)
     * @return
     */
    @Bean
    public InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

配置类三:mybatis

package edu.nf.ch12.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.github.pagehelper.PageInterceptor;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;
import java.util.Properties;

/**
 * @Date 2023-10-30
 * @Author hy
 */
@Configuration
// 扫描dao接口的包,动态生成到接口的代理实现
@MapperScan(basePackages = "edu.nf.ch12.dao")
public class MybatisConfig {

    /**
     * 整合mybatis,装配SqlSessionFactory
     * @param dataSource
     * @return
     * @throws IOException
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DruidDataSource dataSource) throws IOException {
        // 创建SqlSessionFactoryBean
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        // 注入数据源
        factoryBean.setDataSource(dataSource);
        // 注入mybatis其他设置
        factoryBean.setTypeAliasesPackage("edu.nf.ch12.entity");
        // 设置mapper映射文件的路径
        // 先创建一个资源路径解析器来查找源文件
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(resolver.getResources("classpath:mappers/*.xml"));
        // 设置分页插件,创建分页拦截器
        PageInterceptor interceptor = new PageInterceptor();
        // 设置属性
        Properties properties = new Properties();
        properties.setProperty("helperDialect","mysql");
        properties.setProperty("supportMethodsArguments","true");
        properties.setProperty("reasonable","true");
        // 将分页属性设置到拦截器中
        interceptor.setProperties(properties);
        // 最后将分页拦截器设置到SqlSessionFactoryBean的插件中
        factoryBean.setPlugins(interceptor);

        // 返回SqlSessionFactoryBean给容器
        return factoryBean;
    }

}

配置类四:spring主配置

package edu.nf.ch12.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * 主配置类
 * @Date 2023-10-30
 * @Author hy
 */
@Configuration
// 扫描指定的包,装配相关的Bean
@ComponentScan(basePackages = "edu.nf.ch12")
@Import({JdbcConfig.class,MybatisConfig.class, MvcConfig.class})
public class SpringConfig {

}

配置类五:web

package edu.nf.ch12.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * web配置类,用于取代web.xml
 * @Date 2023-10-30
 * @Author hy
 */
@Configuration
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    /**
     * 加载主配置
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    /**
     * 加载mvc的配置类
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    /**
     * 给DispatcherServlet配置url-pattern
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

十七、过滤器/拦截器/监视器的区别

1、过滤器

过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。

Servlet 中的过滤器 Filter 是实现了 javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断等。
其工作原理是,只要你在web.xml文件配置好要拦截的客户端请求,它都会帮你拦截到请求,
此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;
同时还可以进行逻辑判断,如用户是否已经登录、有没有权限访问该页面等等工作,它是随你的web应用启动而启动的,
只初始化一次,以后就可以拦截相关的请求,只有当你的web应用停止或重新部署的时候才能销毁。

在javax.servlet.Filter接口中定义了3个方法

  • void init(FilterConfig filterConfig) 用于完成过滤器的初始化
  • void destroy() 用于过滤器销毁前,完成某些资源的回收
  • void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) 实现过滤功能,该方法对每个请求增加额外的处理

2、拦截器

拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。

拦截器是在面向切面编程中应用的。也就是在你的service或者一个方法前/后调用一个方法。
比如 动态代理就是拦截器的简单实现,可以在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至可以在你抛出异常的时候做业务逻辑的操作。
拦截器不是在web.xml配置的。比如struts在struts.xml配置,springMVC在spring与springMVC整合的配置文件中配置。

在springmvc中,定义拦截器要实现 HandlerInterceptor接口,并实现该接口提供的三个方法

  • preHandle方法:进入Handler方法之前执行。可以用于身份认证、身份授权。比如如果认证没有通过表示用户没有登陆,需要此方法拦截不再往下执行(return false),否则就放行(return true)。
  • postHandle方法:进入Handler方法之后,返回ModelAndView之前执行。可以看到该方法中有个modelAndView的形参。
    应用场景:从modelAndView出发:将公用的模型数据(比如菜单导航之类的)在这里传到视图,也可以在这里同一指定视图。
  • afterCompletion方法:执行Handler完成之后执行。应用场景:统一异常处理,统一日志处理等。

3、监听器

监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。

Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等。

在 javax.servlet.ServletContextListener接口 中定义了2种方法

  • void contextInitialized(ServletContextEvent sce) 监听器的初始化
  • void contextDestroyed(ServletContextEvent sce) 监听器销毁

4、过滤器 和 拦截器的区别

1)拦截器是基于Java的反射机制的,而过滤器是基于函数回调
2)过滤器依赖与servlet容器,而拦截器不依赖与servlet容器
3)拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4)拦截器可以访问action上下文、值栈里的对象,而过滤器不能
5)在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

十八、自定义异常

1、什么是自定义异常类

在开发中根据自己业务的异常情况Q来定义异常类。

2、为什么需要自定义异常类

JAVA中不同的异常类分别表示某一种具体的异常情况,尽管内部有定义好的一些异常情况,但是在实际开发中总是有些异常情况是Sun没有定义过,此时我们根据自己业务的异常情况来定义异常类。

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值