使用SpringMVC框架

系列文章


了解Spring框架(跳转)



前言

Spring MVC是基于Spring框架基础上的, 主要解决了后端服务器接收客户端提交的请求, 并给予响应的相关问题。
MVC = Model + View + Controller

  • Model: 数据模型, 通常由业务逻辑层(Service Layer)和数据访问层(Data Access Object Layer)共同构成
  • View: 视图
  • Controller: 控制器

注: MVC为项目代码的职责划分提供了参考, Spring MVC框架只关心V-C之间的交互, 与M其实没有任何关系

mybatis结果list永远不会为null, 它只new list 没有填数据
他是快速访问数据库的框架,缓存中间结果, 数据库查询超过500w,家用电脑就会慢,优越电脑3000w数据也会慢


提示:以下是本篇文章正文内容,下面案例可供参考

一、环境搭建

运行环境搭建 Tomcat IDEA

  1. 下载Tomcat
  • Tomcat是Apache 软件基金会的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。Tomcat 服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器
  • Tomcat官网(点击跳转)下载压缩包, 并解压到文件夹, 路径最好只包含英文
  1. 在IDEA中创建Maven工程(按图完成操作)
    创建
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
项目正常启动就会弹出页面显示"HelloWorld"

二、项目配置

1.导入依赖

在项目pom.xml文件中导入spring-webmvc依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.14</version>
</dependency>

2.启动配置

  1. src/main/java下创建包cn.qingtian.springmvc作为根包
  2. 在根包下创建配置包config, 并新建Spring框架配置类SpringCofing.class和SpringMVC配置类SpringMvcConfig.class, 写入:

Spring配置类: SpringConfig.class

package cn.qingtian.springmvc.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {
}

Spring MVC配置类: SpringMvcConfig.class

package cn.qingtian.springmvc.config;

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

@Configuration
@ComponentScan("cn.qingtian.springmvc")// 配置springmvc扫描目录
public class SpringMvcConfig {
}
  1. 在根包下创建类SpringMvcInitializer.class用于设置Spring MVC初始化

SpringMVC初始化类SpringInitializer.class, 此类创建在哪个包下都行只要继承AbastractAnnotationConfigDispatcherServletInitializer项目启动就会自动加载此类

package cn.qingtian.springmvc;

import cn.qingtian.springmvc.config.SpringConfig;
import cn.qingtian.springmvc.config.SpringMvcConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

// SpringMVC初始化类, 必须继承AbstractAnnotationConfigDispatcherServletInitializer 抽象注解配置调度服务初始化
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    // 继承后 必须重写 以下三个方法 并加以配置
    @Override
    protected Class<?>[] getRootConfigClasses() {
        // 把Spring配置类对象传入, 配置Spring框架
        return new Class[]{SpringConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        // 把SpringMVC配置类对象传入, 配置SpringMVC框架
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        // 所有以.mvc结尾的请求都会被SpringMVC处理, 图片.png不会被SpringMVC处理, 会直接在resource下查找文件
        return new String[]{"*.mvc"};
    }
}
  1. 在根包下创建 控制器包controller, 并新建 用户处理类UserController.class

用户控制处理 UserController.class

package cn.qingtian.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {
    
    // 请求路径配置
    @RequestMapping("/login.mvc")
    @ResponseBody
    public String login(){
        return "login";
    }
}
  1. 启动测试

启动项目, 在浏览器地址栏中输入http://localhost:8080/login.mvc回车, 页面显示login表示Spring MVC配置和启动成功

三、基本使用

1、RequestMapping注解

@RequestMapping注解的主要作用是配置 请求路径 与 处理请求的方法的映射关系
通常, 在项目中, 推荐为每一个控制器类都配置此注解, 以指定某个URL前缀,

用法:

添加在处理请求的方法上, 就会将注解中配置的路径与注解所在的方法对应上

    // 请求路径配置
    @RequestMapping("/login.mvc")
    @ResponseBody
    public String login(){
        return "login";
    }

添加在控制器类上, 添加后实际每个方法的映射的请求路径是"类上@RequestMapping注解配置的路径+方法上@RequestMapping注解配置的路径"

package cn.qingtian.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {

    // 请求路径配置
    @RequestMapping("/login.mvc")
    @ResponseBody
    public String login(){
        return "login";
    }
}

通过@RequestMapping注解配置路径时, 并不要求各路径使用/作为第一个字符

  • @RequestMapping注解中, 还可以增加method属性, 可以限制客户端的请求方式, 如果不配置method, 则可以使用任何请求方式

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

例子: 配置method参数为POST :

package cn.qingtian.springmvc.controller;

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

@Controller
public class UserController {

    // 请求路径配置, 请求方式设置为POST请求
    @RequestMapping(path = "/login.mvc",method = RequestMethod.POST)
    @ResponseBody
    public String login(){
        return "login";
    }
}

此时在用浏览器向"http://localhost:8080/login.mvc"发起GET请求, 会出现405方法不允许

  • 另外, Spring MVC框架还提供了@RequestMapping的相关注解, 就已经时限制了请求的方式了, 但是除此之外使用方式与@RequestMapping完全相同, 例如:

@GetMapping @PostMapping @PutMapping @DeleteMapping 等等

  • 实际使用中, 一般类上添加@RequestMapping, 在方法上添加@GetMapping等被限制请求方式的注解, 只有方法允许多种方式时, 才使用@RequestMapping

2、ResponseBody注解

@ResponseBody注解表示: 相应正文, 当在处理请求的方法上添加了@ResponseBody注解, 则处理请求的方法的返回值就会直接相应到客户端去, 如果,没有配置此注解, 则处理请求方法返回值表示"视图组件的名称", 当方法返回后, 服务器并不会直接相应, 而是根据"视图组件名称"在服务端找到对应的视图组件, 并处理, 最后. 将处理后的视图响应到客户端去, 这不是前后端分离的做法!

@ResponseBody注解不仅能添加在方法上, 还可以添加在类上, 因为开发模式一般相对统一, 所以, 一般会将此注解添加在控制器类上, 表示此控制器类中所有处理请求的方法都将响应正文

在Spring MVC框架中, 还提供了@RestController注解, 它同时具有@Controller@ResponseBody注解的效果, 所以, 在响应正文的控制器上, 只需要使用@RestController即可

3、转换器

Spring MVC内置了一系列的转化器(Converter), 用于将方法的返回值转换为响应到客户端的数据(并根据HTTP协议补充了必要的数据), 并且, Spirng MVC会根据方法的返回值不同, 自动选取某个转换器, 例如, 当方法的返回值是Stirng时, 会自动使用StringHttpMessageConvertor转换器, 会将方法返回的字符串作为响应正文, 默认响应文档的字符集是ISO-8859-1, 所以在默认情况不支持非ASCII字符

普通字符串不足以表现多项数据, 自行组织成JSON或其他格式成本高, 可以导入jackson-databind依赖, 遇到Spring MVC没有的转换器, 会自动调用此依赖的转换器, 处理为JSON格式数据

<!-- 转换器依赖 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

以上jackson-databind依赖项中也有一个转换器, 当Spring MVC调用处理方法的返回值是框架没有的匹配的, 会自动调用jackson-databind的转换器, 将返回值处理为JSON格式的字符串, 并且会自动将响应头中的Content-Type设置为application/json

例子: 返回自定义类UserVO转换为JSON对象, 响应到浏览器上

<!-- 在项目的pom.xml文件中导入以下依赖 -->
<!-- 转换器依赖 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

cn.qingtian.springmvc.vo下创建自定义类UserVO

package cn.qingtian.springmvc.vo;

public class UserVO {

    private String username;
    private String password;
    private String nick;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNick() {
        return nick;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }

	@Override
    public String toString() {
        return "UserVO{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nick='" + nick + '\'' +
                '}';
    }
}

UserController中写入

package cn.qingtian.springmvc.controller;

import cn.qingtian.springmvc.vo.UserVO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    // 请求路径配置
    @RequestMapping(path = "/login.mvc")
    @ResponseBody
    public UserVO login(){
        UserVO userVO = new UserVO();
        userVO.setUsername("小明");
        userVO.setPassword("123456");
        userVO.setNick("xiaoming");
        return userVO;
    }
}

在次启动项目在浏览器中访问http://localhost:8080/login.mvc

此时出现406错误
在这里插入图片描述解决办法 在SpringMvcConfig类中写入

package cn.qingtian.springmvc.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
@ComponentScan("cn.qingtian.springmvc") // 设置Spring MVC扫描根包
@EnableWebMvc// 启用 WebMVC 或者此类继承 extends WebMvcConfigurationSupport 作用相同
public class SpringMvcConfig {
}

此时页面, 可以正常显示JSON格式的数据

在这里插入图片描述

4、接收请求参数

在Spring MVC中, 当需要接收客户端的请求参数时, 将各参数直接声明为处理请求的方法的参数即可

package cn.qingtian.springmvc.controller;

import cn.qingtian.springmvc.vo.UserVO;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    // 请求路径配置
    @RequestMapping(path = "/login.mvc")
    public UserVO login(){
        UserVO userVO = new UserVO();
        userVO.setUsername("小明");
        userVO.setPassword("123456");
        userVO.setNick("xiaoming");
        return userVO;
    }

    @RequestMapping(path = "/reg.mvc")
    public UserVO reg(String username,String password,String nick){
        UserVO user = new UserVO();
        user.setUsername(username);
        user.setPassword(password);
        user.setNick(nick);
        return user;
    }
}

在浏览器中访问http://localhost:8080/reg.mvc?username="小明"&password="123456"&nick="xiaoming", 返回结果为:

在这里插入图片描述
需要注意:

  • 如果客户端提交的数据中没有匹配名称的参数, 则以上获取的值为null
  • 如果客户端只是提交了匹配名称的参数, 则以上获取到的值将是""(空字符串)
  • 如果客户端提交了匹配名称的参数, 并且值是有效的, 则可以获取到值
  • 名称由服务器端决定, 客户端需要根据以上名称来提交请求参数
  • 处理方法声明参数时, 声明成String以外的类型, 必须考虑是否可以成功转换类型

5、@RequestParam注解

@RequestParam 请求参数注解, 添加在方法的参数上, 用于配置此参数信息
用法:

  1. 配置name属性: 客户端按照此配置的属性提交参数, 否则提交的参数不生效
  2. 配置required属性: 当值为true时, 客户端不提交此参数,出现400错误, 当值为false时, 客户端不提交此参数, 则服务端视此参数为null
  3. 配置defaultValue属性: 配置此请求参数的默认值, 当客户端没有提交此参数时, 此参数默认值为此属性配置的值

如果有多个参数, 可以分装为DTO作为参数, 但是自定义类型参数不能用@RequestParam注解否则回报500错误

也可以将一部分请求参数封装起来, 另一部分直接声明为处理请求的方法的参数

package cn.qingtian.springmvc.dto;
// 新建类

public class UserDTO {

    private String username;
    private String password;
    private String nick;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNick() {
        return nick;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }

    @Override
    public String toString() {
        return "UserDTO{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nick='" + nick + '\'' +
                '}';
    }
}
package cn.qingtian.springmvc.controller;

import cn.qingtian.springmvc.dto.UserDTO;
import cn.qingtian.springmvc.vo.UserVO;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    // 请求路径配置
    @RequestMapping(path = "/login.mvc")
    public UserVO login(){
        UserVO userVO = new UserVO();
        userVO.setUsername("小明");
        userVO.setPassword("123456");
        userVO.setNick("xiaoming");
        return userVO;
    }

    @RequestMapping(path = "/reg1.mvc")
    public void reg1(@RequestParam(required = true) String username,@RequestParam(required = true) String password,
                      @RequestParam(name = "nickname",defaultValue = "自动生成的默认名") String nick){
        System.out.println("UserController.reg1");
        System.out.println("username = " + username + ", password = " + password + ", nick = " + nick);
    }

    @RequestMapping(path = "/reg2.mvc")
    public void reg2(UserDTO userDTO){
        System.out.println("UserController.reg2");
        System.out.println("userDTO = " + userDTO);
    }

    @RequestMapping(path = "/reg3.mvc")
    public void reg3(UserDTO userDTO,@RequestParam(required = false,defaultValue = "100") Integer age){
        System.out.println("UserController.reg3");
        System.out.println("userDTO = " + userDTO + ", age = " + age);
    }
}

此时如果分别访问:
http://localhost:8080/reg1.mvc?username=Tom&password=123456
http://localhost:8080/reg2.mvc?username=Tom&password=123456
http://localhost:8080/reg3.mvc?username=Tom&password=123456
控制台输出为
在这里插入图片描述

6、配置识别中文

HTTP协议, 编码是ISO-8859-1, 它不识别中文, 所以用UTF-8编写代码返回中文时会出现乱码, 具体表现是

编写控制器类处理方法

	// 解决返回客户端数据中文不识别问题
    @RequestMapping(path = "/get.mvc")
    public String get(){
        return "中文识别成功";
    }

此时在客户端访问此路径时会发生乱码:
在这里插入图片描述

解决办法: 配置@RequestMapping注解的属性值为produces = "application/json;charset=utf-8"

    // 解决返回客户端数据中文不识别问题
    @RequestMapping(path = "/get.mvc",produces = "application/json;charset=utf-8")
    public String get(){
        return "中文识别成功";
    }

此时再访问此路径, 发现中文可以正常识别了

在这里插入图片描述

四、RESTFUL

RESTFUL是以一种网络应用程序的设计风格和开发方式, 基于HTTP, 可以使用XML格式定义或JSON格式定义, RESTFUL适用于移动互联网厂商作为业务接口的场景, 实现第三方OTT调用移动网络资源的功能,

RESTFUL的设计风格典型表现: 将某一些唯一的请求参数的值放在URL中, 使之成为URL中的一部分, 如http://www.xxx.com/question/3224234, 3224234是此页面id值, 而不是使用例如?id=3224234的方式方法URL参数中

RESTFUL架构是对MVC架构改进后所形成的一种架构,通过使用事先定义好的接口与不同的服务联系起来。在RESTful架构中,浏览器使用POST,DELETE,PUT和GET四种请求方式分别对指定的URL资源进行增删改查操作。因此,RESTful是通过URI实现对资源的管理及访问,具有扩展性强、结构清晰的特点。

在RESTFUL风格的URL中, 多数是包含了某些请求参数的值, 在使用Spring MVC框架时, 当需要设计这类URL时, 可以使用{名称}进行占位, 并在处理请求的方法的参数列表中, 使用@PathVariable注解请求参数, 既可将占位符的实际值注入到请求参数中

例如

	// 在浏览器中访问http://localhost:8080/3/info.mvc
	// 控制台输出 id=3
	@RequestMapping(path = "/{id}/info.mvc")
    public void info(@PathVariable Long id){
        System.out.println("id = " + id);
    }

以上代码中, URL中使用的占位符是{id}, 方法中参数名称也是id, 就可以直接匹配, 如果占位符名称与参数名称不一致时, 需要在@PathVariable注解中配置占位符中的名称, 例如:

	@RequestMapping(path = "/{userId}/info.mvc")
    public void info(@PathVariable("userId") Long id){
        System.out.println("id = " + id);
    }

在使用{名称}占位符时, 还可以结合正则表达式进行匹配

{占位符名称 : 正则表达式}

例如

@RequestMapping(path = “/{userId:[0-9]+}/info.mvc”)

如上匹配时, 仅当占位符位置是纯数字的URL才会被匹配上, 如果不是纯数字的会出现404错误页面
还需要注意以上模式, 如果有多个处理方法的占位符的正则匹配上了, 但是只有精准匹配的才会被执行, 所以使用占位符的做法并不影响精准匹配的路径
例如

    @RequestMapping(path = "/{id:[0-9]+}/info.mvc")
    public void info(@PathVariable Long id){
        System.out.println("/{id:[0-9]+}/info.mvc");
        System.out.println("id = " + id);
    }

    @RequestMapping(path = "/{id:[a-z]+}/info.mvc")
    public void info(@PathVariable String id){
        System.out.println("/{id:[a-z]+}/info.mvc");
        System.out.println("id = " + id);
    }

    @RequestMapping(path = "/add/info.mvc")
    public void info(){
        System.out.println("/add/info.mvc");
    }

在控制栏中依次输入
http://localhost:8080/123/info.mvc http://localhost:8080/abc/info.mvc http://localhost:8080/abc/info.mvc
控制台输出如下:
在这里插入图片描述

五、统一处理异常

Spring MVC框架提供了统一处理异常的机制, 使得特定种类的异常对应一段特定的代码, 后续, 当编写代码时, 无论在任何位置, 都可以将异常直接抛出, 由统一处理异常的代码进行处理即可

Spring MVC框架默认捕获的异常是 运行时异常

如果需要统一处理异常, 需要自定义方法对异常进行处理, 关于此方法:

  • 注解: 需要添加 '@ExceptionHandler’注解
  • 访问权限: 应该时公有的
  • 返回值类型: 可参考处理请求的方法的返回值类型
  • 方法名称: 自定义
  • 参数列表: 必须包含1个异常类型的参数, 并且可按需添加HttpServletRequest @HttpServletResponse等少量特定类型的参数, 不可以随便添加参数
    例如:

当此方法捕捉到特有异常后, 会把方法返回值响应到客户端

	@RequestMapping(path = "/error.mvc")
    @ResponseBody
    public String error(){
        String str = null;
        str.toString();
        return "ok";
    }

    // 处理此控制器类 所有的空指针异常 并把消息 响应到客户端
    @ExceptionHandler
    @ResponseBody
    public String handlerException(NullPointerException e){
        return "空指针异常";
    }

在浏览器中访问http://localhost:8080/error.mvc, 会出现
在这里插入图片描述

以上处理异常的代码, 只作用于当前控制器类中的各个处理请求的方法, 对其他的控制器类中的代码并不产生任何影响, 无法处理其他控制器类处理请求时出现的异常

为了可以使异常处理机制可以让控制器类所共用:

  • 将处理异常代码放在专门的类中
  • 在此类上添加@ControllerAdvice注解(目前主流的响应方式都是"响应正文", 则可以使用@RestControllerAdvice)

还有一种方法是让所有控制器类继承一个处理异常类, 也可实现异常的统一处理(不推荐), 因为Spring MVC提供了统一异常的机制, 而且java中的类只能单继承

例如:

package cn.qingtian.springmvc.exception.handler;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 处理此控制器类 所有的空指针异常 并把消息 响应到客户端
    @ExceptionHandler
    public String handlerException(NullPointerException e){
        return "Error, NullPointerException";
    }
}

以上异常处理可以允许多个统一处理异常的方法, 如果某个异常能被多个方法处理(异常类型符合多个处理异常的方法的参数类型), 则优先执行最能够匹配的异常处理方法

关于ExceptionHandler可配置注解参数, 再参数中指定异常类型,

例如:

package cn.qingtian.springmvc.exception.handler;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 另一个统一处理异常的方法
    @ExceptionHandler({
            Throwable.class
    })
    public String Exception(Throwable e){
        return "Error, Throwable";
    }

    // 处理此控制器类 所有的空指针异常 并把消息 响应到客户端
    @ExceptionHandler(NullPointerException.class)
    public String handlerException(Throwable e){
        return "Error, NullPointerException";
    }
}

以上异常处理方法, 如果出现空指针异常, 结果是
在这里插入图片描述

六、标准响应类型

开发中, 如果返回的数据类型格式太多或者返回的自定义分装的类太多, 使得不仅不利于管理, 而且不利于复用, 如果定义一个"通用"的数据类型, 无论哪个控制器处理哪个请求, 最终都返回此类型, 不仅利于管理, 而且还可以复用

例如:

cn.qingtian.springmvc.exception中新建自定义异常类ServiceException

package cn.qingtian.springmvc.exception;

import cn.qingtian.springmvc.restful.ResponseCode;

// 自定义异常
public class ServiceException extends RuntimeException{
    // 业务返回码
    private ResponseCode state;

    public ServiceException(ResponseCode state,String message) {
        super(message);
        this.state = state;
    }

    public ResponseCode getState() {
        return state;
    }
}

cn.qingtian.springmvc.restful包下新建ResponseCode枚举类, 为本项目自定义业务返回码

package cn.qingtian.springmvc.restful;

/**
 * 枚举类型, 枚举自定义错误码
 */
public enum ResponseCode {

    OK(200),
    BAD_REQUEST(400),
    UNAUTHORIZED(401),
    FORBIDDEN(403),
    NOT_FOUND(404),
    NOT_ACCEPTABLE(406),
    CONFLICT(409),
    INTERNAL_SERVER_ERROR(500);

    private Integer value;

    ResponseCode(Integer value) {
        this.value = value;
    }

    public Integer getValue(){
        return value;
    }
}

在在cn.qingtian.springmvc.restful包下新建JsonResult类, 为本项目通用返回结果类

package cn.qingtian.springmvc.restful;

import cn.qingtian.springmvc.exception.ServiceException;

/**
 * 通用返回结果类
 */
public class JsonResult<T> {
    // 业务返回码
    private Integer state;
    // 返回消息
    private String message;
    // 返回数据
    private T data;
    // 构造方法私有化, 限制此类创建规则
    private JsonResult(){}
    // 处理成功返回结果
    public static <T> JsonResult<T> ok(T data){
        JsonResult<T> jsonResult = new JsonResult<>();
        jsonResult.state = ResponseCode.OK.getValue();
        jsonResult.data = data;
        return jsonResult;
    }
    public static JsonResult ok(String message){
        JsonResult jsonResult=new JsonResult();
        jsonResult.setState(ResponseCode.OK.getValue());
        jsonResult.setMessage(message);
        jsonResult.setData(null);
        return jsonResult;
    }
    // 处理成功返回结果, 没有返回消息和返回数据
    public static JsonResult<Void> ok(){
        return ok(null);
    }
    // 处理失败返回的结果, 返回结果一般有错误信息和业务返回码, 不包含处理数据结果
    public static JsonResult<Void> fail(ResponseCode state, String message){
        JsonResult<Void> jsonResult = new JsonResult<>();
        jsonResult.state = state.getValue();
        jsonResult.message = message;
        return jsonResult;
    }
    public static JsonResult<Void> fail(ResponseCode state, Throwable e){
        return fail(state,e.getMessage());
    }

    public static JsonResult<Void> fail(ServiceException e){
       return fail(e.getState(),e);
    }
}

七、POJO

对于封装属性的类型, 可以统称为POJO
常见的POJO后缀有: BO DO VO DTO等, 不同的后缀表示不同的意义, 例如: VO = Vaule Object DTO = Data Transfer Object
在一个项目中, 哪些情景下使用哪种后缀没有统一的规定, 通常是各项目内部决定
注意: 在为封装属性的类进行命名时, 以上BO DO VO DTO 等这些后缀的每一个字母都应该是大写的
一般, 前端传递到控制器类中的封装数据后缀是DTO, 由服务器返回给前端的是VO

八、拦截器(Interceptor)

在Spirng MVC框架中, 拦截器是可以运行在所有的控制器类处理请求之前和之后的一种组件, 并且, 如果拦截器运行在控制器处理请求之前, 还可以选择对当前请求进行阻止或放行,主要用于 拦截请求后, 执行某些代码, 它的优势是可作用于若干种不同请求的处理过程, 即: 只写一个拦截器, 就可以在多种请求的处理过程中被执行

什么时候使用: 只要是若干种不同的请求过程中都需要执行相同的或者高度相似的代码, 都可以使用拦截器, 如验证用户是否已经登录等

用法: 写处理规则, 后注册

编写拦截器类, 此类需实现HandlerInterceptor接口, 并重写其中的三个方法

package cn.qingtian.springmvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class LoginInterceptor implements HandlerInterceptor {
    
    // 请求过来前的操作, true为放行, false为拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("LoginInterceptor.preHandle");
        return false;
    }
    // 请求处理返回后的操作, 如果抛出异常则不执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("LoginInterceptor.postHandle");
    }
    // 请求响应完成后的操作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("LoginInterceptor.afterCompletion");
    }
}

注册拦截器, 实现拦截规则, 此类需要实现WebMvcConfigurer接口, 并重写addInterceptor方法

package cn.qingtian.springmvc.config;

import cn.qingtian.springmvc.interceptor.LoginInterceptor;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan("cn.qingtian.springmvc") // 设置Spring MVC扫描根包
@EnableWebMvc// 启用 WebMVC 或者此类继承 extends WebMvcConfigurationSupport 作用相同
public class SpringMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                // 此方法参数可以是 String... 也可以是List<String>
                .addPathPatterns("/login.mvc","/error.mvc");
    }
}

此时, 在访问http://localhost:8080/error.mvc会发现浏览器显示空白, 控制台输出
在这里插入图片描述
如果把perHandler返回值改为true, 再访问http://localhost:8080/error.mvc
在这里插入图片描述
在这里插入图片描述
如果把perHandler返回值改为true, 再访问http://localhost:8080/login.mvc
在这里插入图片描述
在这里插入图片描述

  • 拦截器实现类中, 方法执行顺序是perHandle()>控制器中处理请求的方法>postHandle()>afterCompletion()
  • perHandle()方法返回值是true时, 表示"放行", 为false表示"阻止"
  • 拦截器注册时先调用addInterceptor()方法添加拦截器, 后调用addPathPatterns()方法添加拦截路径, 此方法参数可以是String...List<String>
  • 再编写拦截路径时, 可以用*作通配符, 如/user/*表示/user下的这一层级所有的请求, 如/user/**可以匹配/user下的任意层级请求, 还可以再链式语法中调用excludePathPattern()方法, 以排除登录或者注册等这样的请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值