前言
本篇是快速学习而非深度学习,知识点可能讲的不充分,在保证前置知识掌握扎实的情况下可以学习本篇
第一章 什么是springMvc?
SpringMvc是一个表述层框架
,是对Servlet的封装
。基于Spring框架完成的,继承了高性能的优点,从一开始就包含在Spring Framework中。他的优点如下:
- Spring 家族原生产品,与IOC容器等基础设施无缝对接
- 表述层各细分领域需要解决的问题全方位覆盖 ,提供全面解决方案
- 代码清新简洁,大幅度提升开发效率
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
为什么SpringMvc?
我们看一段代码,直观的感受一下相比于原生的Servlet开发,SpringMvc给我们带来的便利。
java
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userName = request.getParameter("userName");
System.out.println("userName="+userName);
}
less
@RequestMapping("/user/login")
public String login(@RequestParam("userName") String userName,Sting password){
log.debug("userName="+userName);
//调用业务即可
return "result";
}
-
我们通过@RequestMapping注解直接指定是对哪些请求的映射。
-
通过@RequestParam直接将请求中的用户名或其他属性赋值给我们的参数 。根本不需要像上面那样繁琐的步骤重写doGet方法一步步去取出来,我们可以将更多的精力放在对业务逻辑的编写上。
见一叶落,而知岁之将暮;睹一壶之冰,而知天下之寒:以近论远。
这样看来,SpringMvc的代码简洁程度与强大不言而喻!
上面我们看到SpringMvc简化了对前端参数的接收,同时也简化了对前端数据的响应
,后面我们会详细讲。
第二章 SpringMVc如何工作?
我们把整个后端想象成一个向外提供服务的公司,而Controller-》Service-》dao三层组成了生产部(真正产出服务的人) 。而公司的组成绝对不止生产部这么简单,因为再好的东西也需要跟外部建立联系并将他们销售出去 ,这样才能实现它真正的价值。而SpringMvc则承接了其余全部的工作。
公司的CEO ---- DispatcherServlet
DispatcherServlet承接了外部所有的订单 (请求),他主要负责与外部建立联系,并将请求交给不同的部门来处理,并将最终结果返还给客户。
公司的秘书 ---- HandlerMapping
HandlerMapping会承接来自CEO的任务,根据提供的请求路径 去寻找有没有指定的员工(Handler)
可以生产出客户想要的商品。并将相关的结果返回给CEO
公司的经理 ---- HandlerAdapter
我们发现,到目前为止,员工还没有开始工作,因为还没有收到详细的订单信息(前端请求的参数) ,而HandlerAdapter就是负责将CEO提供的客户详细需求(request对象)
简化成员工工作所需要知道的部分(方法的请求参数)
,当员工工作完成后,将返回的结果封装进客户所需要的礼盒(response对象)里,然后返回给CEO。
公司的财务 ---- viewResolver
从上面看,似乎我们已经完成了所有的工作。但别忘了,用户可能会请求一些静态的资源(如html,图片)。而视图解析器内部则是一大堆的路径前缀和后缀
。他会把CEO送来的路径片段(其实是HandlerAdapter手下的Controller提供的)
封装成真实的路径,然后去寻找对应的静态资源,并将他们返回给CEO。当然这一步并非是必须的,也有可能根本不会走这一步。
图解关系组成
我们需要做什么?
- 使用web.xml配置DispatcherServlet让他生效,它是核心,所有的请求都经由他手处理和转发
- HandlerMapping,我们需要配置它并放入IOC容器中,使他生效
- HandlerAdapter,我们需要配置它并放入IOC容器中,使他生效
- Handler,写我们的业务逻辑。
- ViewResolve,同样需要配置它并放入IOC容器中,使他生效。(
前后端分离的项目不需要后端返回页面,无需配置
)
快速上手SpringMvc
创建一个父项目并将它设置为聚合项目pom,并引入以下依赖。(记得改一下maven设置)
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu</groupId>
<artifactId>SpringMvc6</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>pro-01</module>
</modules>
<properties>
<spring.version>6.0.8</spring.version>
<servlet.api.version>9.1.0</servlet.api.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- web相关依赖 -->
<!-- 在 pom.xml 中引入 Jakarta EE Web API 的依赖 -->
<!--
在 Spring Web MVC 6 中,Servlet API 迁移到了 Jakarta EE API,因此在配置 DispatcherServlet 时需要使用
Jakarta EE 提供的相应类库和命名空间。错误信息 "'org.springframework.web.servlet.DispatcherServlet'
is not assignable to 'javax.servlet.Servlet,jakarta.servlet.Servlet'" 表明你使用了旧版本的
Servlet API,没有更新到 Jakarta EE 规范。
-->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>${servlet.api.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
创建子项目并将其改成web项目
本步骤演示如何将普通项目转换为web项目
- 点击项目右击F4或右击选择Open Module Setting,打开模块设置
- 点击加号添加web模块
3. 修改上下两个路径,把要添加的web文件夹以及相关内容全部改到模块下的src\main\
文件夹下。
4. 保存后生效。
创建测试用Controller
less
@Controller
public class helloController {
//该方法返回一个JSON字符串,内容为 hello SpringMvc
@RequestMapping("spring/helloController")
@ResponseBody
public String helloController(){
System.out.println("helloController.helloController");
return "hello SpringMvc";
}
}
将秘书与经理放入IOC并配置CEO
-
我们先声明一个配置类
-
指定包扫描地址
-
我们将HandlerMapping放入IOC,保证SpringMVC中寻找handler路径的模块正常工作。
-
我们将Adapter放入IOC,保证SpringMVC中简化handler所需参数和封装Response的模块正常工作
typescript
//TODO 无需添加Component,因为这些注解内部包含的有
//TODO 在Mvc中,我们无需去自己创建ClassPathXMLApplicationContext自己创建Spring容器
@ComponentScan("com.atguigu")
@Configuration
public class SpringMvcConfig {
//TODO 把我们的秘书-》handlerMapping放入Spring
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(){
return new RequestMappingHandlerMapping();
}
//TODO 把我们的经理-》Adapter放入Spring
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
配置我们的CEO,保证所有请求均由DispatcherServlet来处理
我们需要继承一个初始化抽象类 ,并实现方法找到刚配置的类 ,将所有请求交给它来处理 。我们就不再需要在web.xml中配置DispatcherServlet了。
scala
package com.atguigu.Config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
//TODO 我们这个类存在的意义是为了替代web.xml中手动去配置Servlet
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
//TODO 指定了这个才能让Spring找到他
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
//TODO 表示我们所有的请求全去找它来处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
下载安装配置tomcat10
打个war包并导入
手动打包教学
最终测试
tomcat跑起来后路径上加入我们Controller的地址/spring/helloController
解决tomcat控制台乱码
-
找到专门管日志的配置文件并打开
-
把里面所有的UTF-8换成GBK,这样一来,把转码交给IDEA处理即可
SpringMvc注解详解
1. requestMapping注解以及子注解
① requestMappring用来干嘛的?
requestMapping相当于秘书,用来标记路径 ,指示DispatcherServlet找到指定的方法
。
② requestMappring的属性
我们主要讲2个属性
value属性
用来填写路径,我们主要有以下几个知识点
- 我们对于路径的填写格式相对宽松 ,可以填
/user/login
,也可以是user/login
,又或者是user/login/
- 如果我们希望单个方法处理多个请求 ,可以使用
{"user/login","user/getName"}
的格式来填写
ini
@RequestMapping(value = {"user/login","user/getName"})
- 使用模糊匹配可以解决
某路径下任意子路径的映射
less
@RequestMapping(value = "spring/*") 表示spring/任意字符全部配
@RequestMapping(value = "spring/**") 表示spring/任意层级,任意字符全部匹配
- 如果requestMapping注解里面没有其他要填写的属性,可以直接省略value关键字
kotlin
@RequestMapping("spring/helloController")
method属性
用来定义前端发来的请求类型,spring使用枚举类来存放几个参数。
- 格式为
method = "RequestMethod.GET"
- 如果跟前面的value参数一起写可以试用一下格式
ini
@RequestMapping(value = "spring/helloController",method = RequestMethod.GET)
③ RequestMapping注解放在哪?
可以放在类上面简化方法上的路径,假如一个Controller类全部为关于user的映射 ,而且路径全部为/user/????
,那我们就可以在类上定义一个@RequestMapping("user"),内部的方法直接拼接即可
④ RequestMapping的子注解
less
@GetMapping()
@POSTMapping()
@DeleteMapping()
@PutMapping()
2. RequestParam注解
① RequestParam注解的作用是什么?
RequestParam注解放在请求参数上,把前端请求的参数取出来,赋值给处理方法的参数上,并且提供多种灵活的处理方式
我们来看一组代码
less
@GetMapping("user/login")
@ResponseBody()
public String userLogin(String userName, String password){
System.out.println("userName = " + userName + ", password = " + password);
return "ok";
}
请求页
http://localhost:8080/user/login?userName=jack&password=10010
在上面的代码中,我们没有使用@RequestParam注解,依然可以正常使用,说明这个@RequestParam注解不是必须的
但是如果没有使用该注解,则必须满足前端请求的参数名与后端处理方法的参数名一致,但是参数是可传可不传的 如果不传,int类型的默认值为0
② RequestParam注解解决一名多值
先看一组代码
less
@GetMapping("user/login2")
@ResponseBody()
public String userLogin2(@RequestParam List<String> userName, String password){
System.out.println("userName = " + userName + ", password = " + password);
return "ok";
}
请求页
http://localhost:8080/user/login2?userName=jack&userName=lisa&password=10010
如果我们想用List接收参数(userName由多个值组成),则必须使用@RequestParam注解
③ RequestParam注解参数详解
看一下该注解的源码
less
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
明显可以看到有3个参数
- value参数
value参数用来填写前端的请求参数 ,如果前后端的请求参数名不一致,可以使用该参数正确的将前端参数映射给方法参数
- require参数
该参数默认是false,表示该参数可传可不传
- defaultValue参数
当require参数为true时,可以设置默认参数,当前端没有给出必要的参数时,我们保证代码有兜底
④ 使用对象接收参数
写好pojo,直接指定为参数即可,无需做任何设置,无需使用注解 。但是要求参数名必须与属性名一致
。
如果要求有默认值,则可以直接写到pojo里面
动态路径传参与@PathVariable注解
① 什么是动态路径传参?
动态路径传参就是不使用传统的param格式传参,而是用/username的值/xxx参数的值
,就像下面这个链接,直接传值。这样做接收效率更高
bash
http://localhost:8080/user/jack/1234
服务端写法:
less
@GetMapping("user/{userName}/{password}")
@ResponseBody()
public String userLogin3(@PathVariable String userName, @PathVariable String password){
System.out.println("userName = " + userName + ", password = " + password);
return "ok";
}
- 直接用
/{???}
接收, - 必须使用PathVariable接收
② 相关的参数
直接看源码
less
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
}
- value参数
value参数用来填写前端的请求参数 ,如果前后端的请求参数名不一致,可以使用该参数正确的将前端参数映射给方法参数
- require参数
该参数默认是false,表示该参数可传可不传
3. JSON传参与@RequestBody注解
我们尝试让前端传一个JSON串过来,内容为:{"userName":"jack","age":12}
,
我们使用一个对应的javaBean来接收它:
kotlin
package com.atguigu.POJO;
import lombok.Data;
@Data
public class User {
private String userName;
private Integer age;
}
@RequestBody注解
RequestBody注解放在参数上面,表示将前端的JSON赋值给该值
用对象接收
less
@PostMapping("user/jsonTest")
@ResponseBody()
public String userLogin4(@RequestBody User user){
System.out.println("user = " + user);
return "ok";
}
用Map接收
发送方式与对象格式一致
less
@PostMapping("user/jsonTest")
@ResponseBody()
public String userLogin4(@RequestBody Map user){
return "ok";
}
用List接收
less
@PostMapping("user/jsonTest")
@ResponseBody()
public String userLogin4(@RequestBody List<User> users){
return "ok";
}
JSON传参的问题
下面使用的postMan不会用请移步:PostMan简单使用教学 - 掘金 (juejin.cn)
上面的代码测试后报错如下
报错原因是什么?
这是因为java本身是不支持使用JSON作为参数格式 的,(Spring底层是用java写的
)
解决方法
- 引入JSON相关的依赖。
xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
- 给我们的经理HandlerAdapter赋能(
配置类加上@EableWebMvc
),让他能够完成JSON相关的解析工作
kotlin
package com.atguigu.Config;
import jakarta.servlet.RequestDispatcher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
//TODO 无需添加Component,因为这些注解内部包含的有
//TODO 在Mvc中,我们无需去自己创建ClassPathXMLApplicationContext自己创建Spring容器
//TODO 加上EnableWebMvc 开启Adapter支持JSON
@ComponentScan("com.atguigu")
@Configuration
@EnableWebMvc
public class SpringMvcConfig {
//TODO 把我们的秘书-》handlerMapping放入Spring
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(){
return new RequestMappingHandlerMapping();
}
//TODO 把我们的经理-》Adapter放入Spring
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
好了,正常到这里应该是测试成功了。如果依旧显示上面的报错请移步:手动给java项目打war包 - 掘金 (juejin.cn)
附加知识->关于@EnableWebMvc注解
该注解其实内部不仅给HandlerAdapter增加了JSON处理器,还自动帮我们把经理与秘书放入了IOC容器中 ,所以我们已经不需要手动放入他们了。
我们注释掉它仍然可以运行
less
@EnableWebMvc()
@Configuration
@ComponentScan("com.atguigu")
public class SpringMvcConfig{
//TODO 把我们的秘书-》handlerMapping放入Spring
// @Bean
// public RequestMappingHandlerMapping handlerMapping(){
// return new RequestMappingHandlerMapping();
// }
//TODO 把我们的经理-》Adapter放入Spring
// @Bean
// public RequestMappingHandlerAdapter handlerAdapter(){
// return new RequestMappingHandlerAdapter();
// }
}
获取Cookie与SpringMvc的默认数据接收模式
获取Cookie我们需要使用到新的注解:@CookieValue
他的用法如下:
less
@RequestMapping("t1/sendCookie")
public String getCookie(@CookieValue("userId") String userId){
System.out.println("userId = " + userId);
return "ok!";
}
我们把它加在Handler的参数上,指定要获取的Cookie的kev,就能取到想要的value。
当然,如果我们想要获取cookie,需要提前给客户端设置相应的cookie,所以我们需要先让用户请求,并为它设置cookie
typescript
@GetMapping("t1/getCookie")
public String setCookie(HttpServletResponse response){
Cookie userId = new Cookie("userId", "10010");
response.addCookie(userId);
return "ok!";
}
SpringMvc的默认数据接收模式
这里我想讨论一个东西,就是我们会发现,在上面的代码中,我们并没有设置任何注解,但是我们仍然可以拿到请求中的HttpServletResponse对象 ,包括像我们最初给大家提供的第一套代码,我们并没有设置任何注解,只需要保证Handler参数与前端发送的请求参数一致,就能取到数据。
这是因为HandlerAdapter给我们取到了数据 ,它默认使用Param方式接收参数。一般来讲会有三种接收模式
- Param传参
- JS传承传参
- 动态路径传参
我们会发现,除了第一种默认的Param传参,其他两种都要求必须使用相关注解才能取到参数
。
获取请求头信息
SpringMvc为我们提供了新的注解@RequestHeader注解,用来取出请求头内的数据 ,他的用法略有不同,我们需要指定要取的是请求头内部的哪一条信息,而非整个请求头
。
less
@RequestMapping("t1/getHeader")
public String getHeader(@RequestHeader(value = "host")String host){
System.out.println("host = " + host);
return "host="+host;
}
获取原生对象与3种共享域
还记得我们上面的设置Cookie的代码么?我们直接获取了Response对象,同样,我们获取Request对象的方法也就是直接写上HttpServletRequest即可。
简单复习3种共享域
什么是共享域?
共享域是指在Servlet存储数据,方便数据在web应用中共享和访问。常见的作用域有4种。分别是ServletContext
,HttpServletRequest
,HttpSession
,PageContext
。
他们的应用范围各不相同,他们其实算是服务端对客户端管理时产生的必要产物,客户端是无法拿到这些会话内部数据的,只是方便服务端操作使用
ServletContext作用域
-
它是最大的作用域,可以在整个web应用中使用,也称为Application级作用域,
-
他里面存放的数据在被各个Handler访问时是线程安全的。
-
SpringMvc在初始化时就已经把它初始化并放入IOC容器中 了,我们只需要定义它并使用@AutoWired即可
less
@Controller
@ResponseBody
public class Controller2 {
@Autowired
ServletContext servletContext;
@GetMapping("t1/getCookie")
public String setCookie(HttpServletResponse response){
Cookie userId = new Cookie("userId", "10010");
response.addCookie(userId);
return "ok!";
}
HttpSession作用域
它是范围第二大的作用域,他的实现方法是为每一台客户端建立一个Session会话,并将生成的会话id放到给客户端的Cookie中 ,这样就保证了只要客户端不关闭浏览器,就一直会带上这个cookie ,服务器端依据这个确定客户端是谁,并能找到与其对应的会话。
kotlin
@RequestMapping("t1/testSession")
public String testSession(HttpSession session){
//放置参数。。。获取。。删除。。。
session.setAttribute("jack","jack is happy");
//获取会话创建时间
System.out.println(session.getCreationTime());
//主动让会话失效
session.invalidate();
return "ok";
}
HttpServletRequest作用域
相对较小的作用域,其实就是请求对象本身 ,在这次请求中生效,返回后就不复存在了。
我们通过它也可以拿到我们的Application作用域哦!
typescript
@RequestMapping("t1/testRequest")
public String testRequest(HttpServletRequest request){
//放置参数。。。获取。。删除。。。
request.setAttribute("jack","jack is happy");
request.getServletContext();
return "ok";
}
@RestController注解
该注解是@Controller与@ResponseBody的组合体,表示该类为Controller,而且内部所有Handler方法的内容全部以JSON格式打包返回。 注意注意,该注解与@RequestMapping注解没有关系!!!!!
RestFul风格
restFul风格是依据Http协议的设计理念延伸出来的一种代码风格。对我们接口的设计做了同一的规范,使接口的设计更简单明确。
简单来讲就是将URI定义为名词,而诉求则使用不同的请求方法来区别。
而请求参数的传递则依据情况来定,非敏感的单个数据尽量使用路径传参,范围数据则使用Param传参,对于请求体或敏感数据则使用JSON传参
RestFul风格不能解决所有问题,一个固定的URI也不可能无限次使用,数量不够时可以使用不同的URI
restFul风格实际演示
less
package com.atguigu.Controller;
import com.atguigu.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController()
@RequestMapping(value = "user",produces = "application/json;charset=utf-8")
public class UserController {
//TODO 单个数据尽量使用路径传参,并且使用名词定义URI~~
//TODO get请求用GetMapping
@GetMapping("/{userid}")
public User getUserById(@PathVariable() int userid){
User user = new User();
user.setId(userid);
user.setName("jack");
user.setAge(12);
return user;
}
//TODO 单个数据尽量使用路径传参,并且使用名词定义URI~~
//TODO delete请求用DeleteMapping
@DeleteMapping("/{userid}")
public String deleteUserById(@PathVariable int userid){
System.out.println("此处省略删除步骤");
System.out.println("aaaa");
return "删除成功";
}
//TODO 单个数据尽量使用路径传参,并且使用名词定义URI~~
//TODO delete请求用PutMapping
@PutMapping("/{userid}")
public String putUserById(@PathVariable int userid){
System.out.println("此处省略保存步骤");
System.out.println("aaaa");
return "删除成功";
}
//TODO 多个数据或范围数据用Param传参
@GetMapping()
public List<User> getPage(@RequestParam int page,@RequestParam int size){
System.out.println("page = " + page + ", size = " + size);
User user = new User();
user.setId(1001);
user.setName("jack");
user.setAge(12);
ArrayList<User> users = new ArrayList<>();
users.add(user);
return users;
}
//TODO 敏感数据用请求体
@PostMapping
public String saveUserByIdAndPassword(@RequestBody Map<String,Object> userInfo){
System.out.println(userInfo.get("userName"));
System.out.println(userInfo.get("password"));
System.out.println("我省略了更改用户信息~~~~");
return "ok~";
}
}
自定义异常处理
Spring使用AOP向我们生成了两个新的注解,它存在的目的是将异常处理从代码中抽取出来,进行更规范统一的处理。
- 注解@RestControllerAdvice
- 注解@ExceptionHandler
@RestControllerAdvice
一般放在类上面。表示该类内部的方法为异常处理方法,当发生异常时,不会优先使用Java的报错,而是进入该类寻找对应的Handler方法来处理异常
@ExceptionHandler
放在对应的处理方法上面,注解内部需要指定对应的异常,表示该异常由该方法进行处理 ,异常处理遵循细化方法作针对处理 ,没有细化的异常处理则会被更大范围的异常处理兜底。
代码实战
kotlin
package com.atguigu.MyExceptionHandler;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public Object nullPointerExceptionHandler(Exception exception){
System.out.println("空指针异常!!!->报错为"+exception.getMessage());
return exception.getMessage();
}
@ExceptionHandler(Exception.class)
public Object ExceptionHandler(Exception exception){
System.out.println("报错啦~~~~~~(大异常)"+exception.getMessage());
return exception.getMessage();
}
}
另起一篇(下篇地址)
这东西写多了页面会非常卡,根本写不了。另起一篇来写剩余内容 地址为: