一:Springmvc简介
1.简介:
Spring Web MVC 是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC” 来自其源模块名称(spring-webmvc)但它通常被称为“Spring Mvc”
在控制层框架历经 Strust ,WebWork,Strust2等诸多产品的历代更迭之后,目前业界普遍选择了Spring MVC 作为JavaEE 项目表述层开发的首先方案。
优势:
》Spring 家族的原生产品,与IOC容器等基础设施无缝对接
》表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
》代码清新简洁,大幅度提升开发效率
》 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
》性能卓著,尤其适合现代大型/超大型互联网项目要求
2.作用:
3.核心组件:
1.DispatcherServlet:SpringMVC提供,我们需要使用web.xml配置使其生效,它式整个流程处理的核心,所有请求都经过它的处理和分发
2.HandlerMapping:SpringMVC提供,我们需要进行Ioc配置使其假如Ioc容器方可生效,它内部缓存handler和handler访问路径数据,被DispatcherServlet调用,用于查找路径对应的handler!
3.HandlerAdapter:SpringMVC提供,我们需要进行Ioc配置使其假如Ioc容器方可生效,它可以
处理请求参数和处理响应数据,每次DispatcherServlet都是通过HandlerAdapter间接调用handler,它是handler和DispatcherServlet之间的适配器
4.Handler:handler又称为处理器,它是Controller类内部方法的简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果!
5.ViewResovler: SpringMVC提供,我们需要进行Ioc配置使其假如Ioc容器方可生效,视图解析器主要作用简化模板视图页面查找的,但是需要注意,前后端分离项目,后端只返回JSON数据,不返回界面,那就不需要视图解析器,相对其他组件不是必须的。
二:快速入门程序
步骤1:创建项目并导入依赖:
<dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-web-api</artifactId> <version>9.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.6</version> </dependency>
步骤2:创建控制层处理器并添加注解
@Controller public class HelloHandler { @RequestMapping("spring/hello")//配置访问路径 @ResponseBody //返回前端字符串,不调用视图解析器 public String hello(){ System.out.println("hello handler"); return "hello springmvc"; } }
步骤3:创建配置类
@Configuration @ComponentScan("com.cn.handler") public class MyConfig { @Bean public RequestMappingHandlerMapping getRequestMapping(){ RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping(); return requestMappingHandlerMapping; } @Bean public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter(){ RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter(); return requestMappingHandlerAdapter; } }
步骤4:加载配置类并初始化容器
package com.cn.config; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.server.adapter.AbstractReactiveWebInitializer; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; } //指定配置类 @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{MyConfig.class}; } //设置DispatcherServlet的处理路径,一般情况下 /代表处理所有请求 @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
步骤5:工程设置为web工程,并部署到tomcat(10.0以上版本)
1. 工程右键-选择JBLJavaToWeb 把工程设置为web工程
2.把工程部署到tomcat,并重启服务
3.浏览器地址输入:http://localhost:8080/spring/hello
4.浏览器显示:hello springmvc 表示程序运行成功
三:Spring MVC接收数据
1.访问路径设置:
@RequestMapping注解的作用就是将请求的URL地址和处理请求的方式(handler 方法)关联起来,建立映射关系。
SpringMVC接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求。@RequestMapping(不用必须使用/开头) user/login
1.精准地址【1个|多个】/user/login {"地址1","地址2"}
2.支持模糊 * 任意一层字符串| **任意层任意字符串
/user/* -> /user/a user/aaaa 可以, /user/a/b 不行
/user/** -> /user/a /user/a/a/a/a
3.类上和方法上添加@RequestMapping的区别
类上提取通用的访问地址
方法上时具体的handler地址
访问: 类地址+方法地址即可
4.请求方式指定
客户端-> http(get|post|put|delete)->ds->handler
默认情况:@RequestMapping("login")主要地址正确,任何请求方式都可以访问
指定请求方式:method={RequestMethod.GET,RequestMethod.POST}
不符合请求方式:会出现405异常!
5注解进阶:
get @GetMapping ==@RequestMapping(xxx,method=GET);
post@PostMapping ==@RequestMapping(xxx,method=POST);
put@PUTMapping ==@RequestMapping(xxx,method=PUT);
delete@DeleteMapping ==@RequestMapping(xxx,method=DELETE);
2.参数接收:
2.1 param和json参数比较
在http请求中,我们可以选择不同的参数类型,如 param 类型和JSon类型。下面对这两种参数类型进行区别和对比:
1.参数编码:
param 类型的参数被编码为ASCII码。JSON类型会被编码为UTF-8
2.参数顺序:
param类型的参数没有顺序限制。但是,JSON类型的参数是有序的。JSON采用键值对的形式进行传递,其中键值对是有序排列的
3.数据类型:
param类型的参数仅支持字符串类型,数值类型和布尔类型等简单数据类型。而JSON类型的参数则支持更复杂的数据类型,如数组,对象等。
4.嵌套性:
param类型的参数不支持嵌套。但是,JSON类型的参数支持嵌套,可以传递更为复杂的数据结构。
5.可读性:
param 类型的参数格式比JSON类型的参数更加简单,易读。但是JSON格式在传递嵌套数据结构时更加清晰易懂。
总的来说,param类型的参数适用于单一的数据传递,而JSON类型的参数则更适用于更复杂的数据结构传递。根据具体的业务需求,需要选择合适的参数类型。在实际开发中,常见的做法是:在GET请求中采用param类型的参数,而在POST请求中采用JSON类型的参数传递。
2.2 param接收参数:
@Controller @RequestMapping("user") public class MyHandler { /* * 1 直接接收 * /user/login?name=root&age=18 * 形参列表,填写对应名称的参数即可!请求参数名=形参参数名即可! * 1)名称相同 * 2)可以不传递,不报错 * * */ @RequestMapping("/login") @ResponseBody public String login(String name,int age){ System.out.println("name = " + name + ", age = " + age); return "name = " + name + ", age = " + age; } /* * 2 注解指定 * 指定任意的请求参数名,要求必须传递 ,要求不必须传递,给一个默认值 * /user/login?account=root&age=18 * account必须传递 ,page可以必须传递,如果不传递默认值就是1 @RequestParam-> 形参列表 指定请求参数名 或者是否必须传递,或者非必须传递设置默认值 用法:@RequestParam(value="指定请求参数名,如果形参名和请求参数名一致,可以省略!", required=false 前端是否必须传递此参数,默认是必须,不传400异常!, * defaultValue="1" 当非必须传递false,可以设置默认值) * * */ @RequestMapping("/login2") @ResponseBody public String login2(@RequestParam("account")String name, @RequestParam(required = false,defaultValue = "10") int age){ System.out.println("name = " + name + ", age = " + age); return "name = " + name + ", age = " + age; } /* * 3 特殊值 * /user/login3?hbs=吃&hbs=喝 * 不加注解@RequestParam 将hbs对应的一个字符串直接赋值给集合! 类型异常! * 加了注解,会将集合加入对应的字符串 * */ @RequestMapping("/login3") @ResponseBody public String login3(@RequestParam List<String> hbs){ System.out.println(hbs); return hbs.toString(); } /* * 4 使用实体对象接值 * /user/login4?name=tom&age=10 准备一个对应属性和get|set 方法的实体类即可, * 形参列表声明对象参数即可! * */ @RequestMapping("/login4") @ResponseBody public String login3(User user){ System.out.println("name = " + user.getName() + ", age = " + user.getAge()); return "name = " + user.getName() + ", age = " + user.getAge(); } }
2.3 路径传参:
@Controller @RequestMapping("path") @ResponseBody public class PathHandler { // path/用户名/密码 //动态路径设计{key} //必须使用 注解@PathVariable @RequestMapping("{name}/{password}") public String hello(@PathVariable String name , @PathVariable String password){ System.out.println("name = " + name + ", password = " + password); return "name = " + name + ", password = " + password; } }
2.4 JSON数据接收(重点):
前端传递JSON数据时,SpringMVC 框架可以使用@RequestBody 注解 来将JSON
数据转换为Java对象,@RequestBody 注解表示当前方法参数的值应该从请求体中获取,并且需要指定value 属性来指示请求体应该映射到哪个参数上,其使用方式和示类代码如下:
步骤1 .前端发送JSON数据(使用postman)
{"name":"zhangsan","age":18,"gender":"男"}
步骤2.定义一个用于接收JSON数据的Java 类
@Data public class Person { private String name; private int age; private String gender; }
步骤3.在控制器中使用@RequestBody注解来接收JSON数据,并将器转换为Java对象:
@Controller
@RequestMapping("json")
@ResponseBody
public class JsonHandler {
@PostMapping("data")
public String data(@RequestBody Person person){
System.out.println("person = " + person);
return person.toString();
}
}
步骤4:添加JSON解析依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.0</version> </dependency>
步骤5:在配置类添加注解:@EnableWebMvc,给SpringMVC HandlerAdpater配置JSON转换器
@EnableWebMvc @Configuration @ComponentScan("com.cn.json") public class MyConfig {}
步骤6:测试并查看响应数据:
Person(name=zhangsan, age=18, gender=nan)
2.5 cookie和Header接收:
1.使用@CookieValue 注解获取cookie数据
存取cookie
@GetMapping("save") public String save(HttpServletResponse httpResponse){ Cookie cookie = new Cookie("cookieName","cookieValue"); httpResponse.addCookie(cookie); return "ok"; }
获取cookie
@RequestMapping("data") public String data(@CookieValue(name="cookieName") String value){ System.out.println("value = " + value); return value; }
2.使用注解@RequestHeader 获取header信息
@Controller @ResponseBody @RequestMapping("header") public class HeaderController { @GetMapping("data") public String data(@RequestHeader(value = "Host") String host){ System.out.println("host = " + host); return host; } }
2.6 接收数据总结:
四:Spring MVC响应数据
1.开发模式介绍:
在Web开发中,有两种主要的开发模式:前后端分离和混合开发
前后端分离模式(重点)
指将前端的界面和后端的业务逻辑通过接口分离开发的一种方式。开发人员使用不同的
技术和框架,前端开发人员主要负责界面的呈现和用户交互,后端开发人员主要
负责业务逻辑和数据存储。前后端通信通过API接口完成,数据格式一般使用JSON
或XML。前后端分离模式可以提高开发效率,同时也有助于代码重用和维护。
混合开发模式:
指将前端和后端的代码集成在同一个项目中,共享相同的技术栈和框架。这种模式在
小型项目中比较常见,可以减少学习成本和部署难度。但是,在大型项目中,这种模式
会导致代码耦合性很高,维护和升级难度较大。
2.快速返回逻辑视图:
1.创建项目并添加依赖:
<dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>3.0.0</version> </dependency>
2. 在WEB-INF下创建视图目录和jsp文件:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <font color="red">${data}</font> </body> </html>
3. 在配置类下配置视图解析器
@Configuration @ComponentScan("com.cn.controller") @EnableWebMvc public class Myconfig implements WebMvcConfigurer { // 视图解析器,指定前后缀 public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp("/WEB-INF/views/",".jsp"); } }
4.创建handler
@Controller @RequestMapping("jsp") public class JspHandler { /* * 快速查找视图方法 * 1.方法的返回值是字符串类型 * 2.不能添加ResponseBody,直接返回字符串给浏览器,不找视图,不走视图解析器 * 3.返回值 对应中间的视图名称即可 * */ @GetMapping("index") public String data(HttpServletRequest request){ request.setAttribute("data","hello jsp!"); return "index"; } }
5.创建初始化接口
import com.cn.config.Myconfig; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{Myconfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
6.转换为web项目部署到服务器 并测试:
浏览器输入:http://localhost:8080/jsp/index
3.转发重定向:
@Controller @RequestMapping("jsp") public class JspHandler { /* * 快速查找视图方法 * 1.方法的返回值是字符串类型 * 2.不能添加ResponseBody,直接返回字符串给浏览器,不找视图,不走视图解析器 * 3.返回值 对应中间的视图名称即可 * * * */ @GetMapping("index") public String data(HttpServletRequest request){ request.setAttribute("data","hello jsp!"); return "index"; } /* * 转发:只能是项目下的资源 * 1.方法的返回值写成字符串 * 2.不能添加ResponseBody注解 * 3.返回的字符串前 forward:+/转发地址 * * */ @GetMapping("forward") public String forward(){ System.out.println("jsp forward"); return "forward:/jsp/index"; } /* * 重定向:即可以是项目下的资源,也可以是项目外的资源 * 1.方法的返回值写成字符串 * 2.不能添加ResponseBody注解 * 3.返回的字符串前 redirect:+/转发地址 * * */ @GetMapping("redirect") public String redirect(){ System.out.println("jsp redirect"); return "redirect:/jsp/index"; } @GetMapping("redirect/baidu") public String redirectbaidu(){ System.out.println("jsp redirect"); return "redirect:http://www.baidu.com"; } }
4.返回JSON数据(重点):
步骤1:新建项目并导入依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.0</version> </dependency>
步骤2:创建配置类
@Configuration @ComponentScan("com.cn.handler") @EnableWebMvc public class MyConfig { }
步骤3:创建SpringMvc初始化类
package com.cn.init; import com.cn.config.MyConfig; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{MyConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
步骤4:创建 返回的json对应的实体类
import lombok.Data; @Data public class User { private String name; private String gender; private int age; }
步骤5:创建Handler
@Controller @RequestMapping("json") @ResponseBody//返回json的注解,不找视图 public class JsonHandler { //返回单个实体类的json数据 @GetMapping("data") public User data(){ User user =new User(); user.setName("zhangsan"); user.setAge(18); user.setGender("man"); return user; } //返回集合对应的json数据 @GetMapping("data2") public List<User> data2(){ List<User> list =new ArrayList<>(); User user1 =new User(); user1.setName("zhangsan"); user1.setAge(18); user1.setGender("man"); User user2 =new User(); user2.setName("lisi"); user2.setAge(20); user2.setGender("woman"); list.add(user1); list.add(user2); return list; } }
步骤6:部署并测试:
浏览器输入地址:http://localhost:8080/json/data
返回结果:
{"name":"zhangsan","gender":"man","age":18}
浏览器输入地址:http://localhost:8080/json/data2
[{"name":"zhangsan","gender":"man","age":18},{"name":"lisi","gender":"woman","age":20}]
5.访问静态资源:
在配置类中重写方法,开启静态资源查找
@Configuration @ComponentScan("com.cn.handler") @EnableWebMvc public class MyConfig implements WebMvcConfigurer { /* 开启静态资源查找 dispatcherServlet->handlerMapping 找有没有对应的handler->没有,找有没有静态资源 * */ @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
五:其他扩展功能
1.restful 介绍和理解:
1)简介:
2)设计规范:
3)实战
1.需求
2.设计
3.实现:
package com.cn.controller; import com.cn.pojo.User; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("user") public class UserController { //分页查询 @GetMapping public List<User> page(@RequestParam(required = false,defaultValue = "1") int page ,@RequestParam(required = false,defaultValue = "10") int size){ return null; } //用户添加 @PostMapping public User save(@RequestBody User user){ return user; } //用户详情 @GetMapping("{id}") public User detail(@PathVariable int id){ return null; } //用户更新 @PutMapping() public User update(@RequestBody User user){ return user; } //用户删除 @DeleteMapping("{id}") public int delete(@PathVariable int id){ return 0; } //用户模糊 public List<User> search(String keyword,@RequestParam(required = false,defaultValue = "1") int page,@RequestParam(required = false,defaultValue = "10") int size){ return null; } }
2.全局处理异常:
1.异常处理的方式:
2全局异常处理步骤:
步骤1:声明全局异常处理类并添加注解@RestControllerAdvice
步骤2:在该类中通过添加注解@ExceptionHandler(指定异常.class) 声明handler方法,处理异常
步骤3:在配置类中扫描类中把该包加进去
3.实战:
1)产生异常的handler
@RestController @RequestMapping("user") public class UserHandler { @GetMapping("data") public String data(){ String s1=null; int length = s1.length();//java.lang.NullPointerException return "ok"; } @GetMapping("data1") public String data1(){ int i= 10/0;// java.lang.ArithmeticException: / by zero return "ok2"; } }
2)全局处理异常的类
package com.cn.excption; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @RestControllerAdvice public class GlobelExceptionHandler { // 发生异常->ControllerAdvice 注解的类型-》 @ExceptionHandler(指定异常类型)-》handler @ExceptionHandler(NullPointerException.class) public Object PowerPointHandler(NullPointerException e){ String message = e.getMessage(); return message; } @ExceptionHandler(Exception.class) public Object OtherHandler(Exception e){ String message = e.getMessage(); return message; } }
3)把异常处理类添加到配置类扫描中,初始化类省略(SpringMvcInit)
@Configuration @ComponentScan({"com.cn.handler","com.cn.excption"}) @EnableWebMvc public class Myconfig { }
3.拦截器:
1.拦截器和过滤器区别:
2.拦截器使用:
步骤1:创建拦截器:
public class MyInterceptor implements HandlerInterceptor { @Override //在处理请求的目标handler方法前执行 //一般用于编码格式设置,登录保护,权限处理 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle------------------"); //返回true 放行,返回false:不放行 return true; } @Override //在目标handler方法之后,handler报错不执行! //此方法只有在preHandle返回true后才执行, 对结果处理,敏感词汇检查 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle------------------"); } @Override //渲染视图之后执行,一定执行 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion------------------"); } }
步骤2:在配置类中开启拦截器,并设置拦截路径
@Configuration @ComponentScan("com.cn.handler") @EnableWebMvc public class MyConfig implements WebMvcConfigurer { @Override //开启拦截器 public void addInterceptors(InterceptorRegistry registry) { //拦截所有 // registry.addInterceptor(new MyInterceptor()); //拦截指定地址 registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/data1"); } }
4.参数校验注解jsr303:
1.校验概述:
jsr303 是java为Bean数据合法性校验提供的标准框架,他已经包含在JAVAEE6.0标准中,jsr303通过在Bean属性上标注类似于@NotNull,@Max等标准的注解指定校验规则,并通过标准的接口对Bean进行验证。
2.校验实现:
步骤1:导入jar包
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator-annotation-processor</artifactId> <version>8.0.0.Final</version> </dependency> </dependencies>
步骤2:在实体类添加校验注解
@Data public class User { /* 1.name 不为null和空字符串 字符串@NotBlank 集合@NotEmpty 包装类@NotNull 2.password长度大于6 3.age必须》=1 4.email 邮件格式的字符串 5.birthday过去实际 * * * */ @NotBlank private String name; @Length(min = 6) private String password; @Min(1) private int age; @Email private String email; @Past private Date birthday; }
步骤3:handler 添加注解@Validated,如果自定义返回异常,添加BindingResult,获取错误信息
@RestController @RequestMapping("user") public class RegisterHandler { /* * 步骤1:实体类添加校验注解 * 步骤2:handler(@Validated 实体类 对象) * 细节:param|json校验都有效果 * json参数-@RequestBody * 如果不符合校验规则,直接向前端抛出异常 * 接收绑定错误信息,自定义返回结果,约定参数错误-》{code:400} * * 捕捉绑定信息 * 1.handler(校验对象,BindingResult result)要求:BindingResult必须紧挨着校验对象 * 2.BindingResult获取绑定错误 * * */ @PostMapping("register") public Object register(@Validated @RequestBody User user){ // 自定义返回异常代码 // public Object register(@Validated @RequestBody User user, BindingResult result){ // if(result.hasErrors()){ // Map map = new HashMap(); // map.put("code",400); // map.put("msg","参数校验异常"); // return map; // // } return user; } }
步骤4:测试
1)正常情况:
2)自定义异常: