系列文章
文章目录
前言
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
- 下载Tomcat
- Tomcat是Apache 软件基金会的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。Tomcat 服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器
- Tomcat官网(点击跳转)下载压缩包, 并解压到文件夹, 路径最好只包含英文
- 在IDEA中创建Maven工程(按图完成操作)
项目正常启动就会弹出页面显示"HelloWorld"
二、项目配置
1.导入依赖
在项目pom.xml文件中导入spring-webmvc依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.14</version>
</dependency>
2.启动配置
- 在
src/main/java
下创建包cn.qingtian.springmvc
作为根包 - 在根包下创建配置包
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 {
}
- 在根包下创建类
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"};
}
}
- 在根包下创建 控制器包
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";
}
}
- 启动测试
启动项目, 在浏览器地址栏中输入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
请求参数注解, 添加在方法的参数上, 用于配置此参数信息
用法:
- 配置
name
属性: 客户端按照此配置的属性提交参数, 否则提交的参数不生效 - 配置
required
属性: 当值为true
时, 客户端不提交此参数,出现400错误, 当值为false
时, 客户端不提交此参数, 则服务端视此参数为null - 配置
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()
方法, 以排除登录或者注册等这样的请求