前面一章节:springmvc最详细的开发流程(上)
链接: springmvc最详细的开发流程(上)-CSDN博客
一、路径注解及参数设置
1.1. @RequestMapping细节介绍
默认情况:只要地址正确,不写请求方式都可以访问
不符合请求方式:报错405
1.2. param和json的区别
- 格式:
param:key = value & key = value
json:(key:value,key:value)
- 参数编码:
param是ASCII编码,所以中间有空格都会变为&,例如:node js,会被编码为node&js
josn是utf-8的编码格式
- 顺序限制:
param没有顺序限制,json需要讲究顺序
- 嵌套性:
param没有嵌套,而json是可以多层嵌套的
1.3. Json数据接收
1.3.1.创建一个类,使用json格式接收数据
1.3.2. 使用postman调用,发现报错信息415
1.3.3. “415”是不支持数据类型错误,为啥?
原因:java原生的api只支持路径参数和param参数,也就是request.getParameter("key"),不支持json;json是前端的格式。
解决方法:1.导入json处理的依赖;2.handlerAdapt配置json转换器,依次完成以上两部,就可以解决json返回的问题。
- 前置准备:导入jackson依赖,为的是下文的@EnableWebMvc注解可以使用
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
- 添加json数据转化器,使用@EnableWebMvc注解,同时,去掉SpringMvcConfig中原有的两个方法
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器,同时它还会配置handlerMapping和handlerAdapt
@Configuration
@ComponentScan(basePackages = "com.samcode.controller")
public class SpringMvcConfig implements WebMvcConfigurer {}
完成上面两个步骤,就可一解决415异常码的问题。
二、共享域的对象操作
2.1.回顾共享域
在 JavaWeb 中,共享域指的是在 Servlet 中存储数据,以便在同一 Web 应用程序的多个组件中进行共享和访问。常见的共享域有四种:ServletContext、HttpSession、HttpServletRequest、PageContext。
简单来说,我想从servlet1跳转或重定向到servlet2,我们跳转和重定向是无法直接携带数据的,所以我们会存到一个共享空间。
在Java Servlet技术中,确实存在四种常见的共享域对象,括号中代码作用范围:
1. ServletContext(整个项目):
- 是一个全局的、与整个Web应用程序(或Servlet容器)相关的共享区域。 - 存储在ServletContext中的数据在整个应用生命周期内对所有用户可见,并且可以跨多个请求和响应共享。 - 重定向和转发时,由于ServletContext是全局作用域,所以存储的数据仍然可以访问。
2. HttpSession(一次会话的一个浏览器多次请求):
- 提供了基于用户的会话级别的存储空间,每个用户都有独立的HttpSession对象。 - 在一次会话的多次请求和响应之间可以共享数据,但不是全局共享,只对该特定会话的用户有效。 - 转发时,由于请求仍属于同一会话,因此可以在转发前后访问HttpSession中的数据;重定向时,浏览器收到新的URL并发起新请求,但仍可以通过包含session ID的cookie来保持会话状态,从而访问到相同HttpSession中的数据。
3. HttpServletRequest(一次请求/转发):
- 表示单次HTTP请求,它提供了一个请求作用域的共享区域。 - 请求作用域内的数据只能在当前请求和响应过程中使用,一旦请求结束,这些数据就会失效。 - 在请求转发场景下,请求对象从一个Servlet传递到另一个Servlet时,其属性可以在转发链路上共享。但在重定向后,原请求对象会被丢弃,新请求会产生一个新的HttpServletRequest对象,所以原请求携带的数据不会自动传递给新的请求。
4. PageContext:
- 是JSP页面的上下文对象,它封装了与当前页面执行相关的所有四个作用域(page、request、session、application),并提供了在这些作用域之间存取数据的方法。 - PageContext的作用域局限于当前JSP页面及其嵌套的包含页,如果涉及到页面之间的转发或重定向,那么该作用域下的数据通常无法在目标页面直接获取。
总结来说,对于转发操作,不同作用域的对象可以实现一定程度的数据共享;而对于重定向,由于创建了新的请求,只有HttpSession这种会话级作用域能够在重定向后继续保持数据的有效性。请求本身(即HttpServletRequest)不支持迭代数据,它的生命周期仅限于一次HTTP请求-响应过程。
2.2.代码
三、springmvc的开发模式框架(重点)
3.1.混合开发模式
- 流程:
前端浏览器访问我们的程序—>依次经过三层架构获取到数据再return回到controller—>将数据存储在共享域中—>模板页面在共享域中取数据—>返回浏览器
- 总结:三层架构+模板语言(jsp/Thymeleaf)
- 优势:项目小,需要全栈,成本低
- 劣势:只能访问html,也就是浏览器访问,其他端无法访问(app,ios,webchat小程序)
3.2. 前后端分离模式
- 优势:后端可更加注重业务逻辑,后续可扩展性强,可做微服务,分布式
- 劣势:项目大、成本高
四、配置视图解析器
4.1. 配置类中实现接口
说明:在配置类中实现接口WebMvcConfigurer,重写configureViewResolvers方法,添加前后缀即可。
4.2. 创建jsp文件
4.3. 新建Controller,并启动项目访问改controller路径
注意:该controller不能有@RequestBody注解,否则回返回字符串给浏览器。没有这个注解的情况下是返回视图名称找到视图。
@Controller
@RequestMapping("/view")
public class ViewController {
@RequestMapping(value = "/jsp")
public String viewJsp() {
System.out.println("jsp");
return "index";
}
}
五、转发和重定向写法:
5.1. 使用spring mvc的写法如下:
下面这两个方法最后都是去访问
localhost:端口/项目上下文路径/view/jsp这个路径
//转发
@RequestMapping(value = "/forward")
public String forward() {
return "forward:/view/jsp";
}
//重定向,可以为内部资源,也可以为外部资源,如果是外部资源就写全路径
@RequestMapping(value = "/redirect")
public String redirect() {
return "redirect:/view/jsp";
}
5.2. 不使用springmvc写法,也就是用request和response对象api
- 转发:可以省略全路径的写法,直接写 /jsp/index
- 重定向:不可省略,必须写全路径。
5.3. @ResponseBody
只要使用了该注解,快速查找视图,转发和重定向都不生效了。
六、静态资源的访问(路径直接访问)
6.1. 新建静态资源文件直接路径访问
6.2. 启动项目,访问资源
http://localhost:7774/springmvc/images/sun.png
发现该路径访问后404,找不到资源
6.3. 原因及解决办法
- 原因:
springmvc处理路径的时候,都是先交给dispatcherservlet,然后再将请求交给handlerMapping,找类中的方法又没有这个路径的,没有就是404。所以路径找的是Handler,而不是一个资源。
- 解决:
实现的WebMvcConfigurer接口中,重写另外一个方法configureDefaultServletHandling,并调用enable()。说明:请求先找dispatcherservlet,接着找handlerMapping,没有匹配到就继续找静态资源。
七、Restful风格开发
内容较少,较为基础,本片暂不介绍
八、异常处理及拦截器
8.1. 异常类型
- 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
- 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws 或@ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。
8.2. 声名式异常的开发
8.2.1. 新建全局异常处理类
/** * 全局异常类,发生异常会走该类
* @author SamY
* @date 2024/01/25
*/
//@ControllerAdvice 可以返回逻辑视图
@RestControllerAdvice // 可以返回json,该注解就是 @ResponseBody + @ControllerAdvice
public class GlobalExceptionHandler {
/**
* 当发生空指针异常会触发此方法!
*/
@ExceptionHandler(NullPointerException.class)
public Object handlerNullException(NullPointerException e){
return e.getMessage();
}
/**
* 所有异常都会触发此方法!但是如果有具体的异常处理Handler!
* 具体异常处理Handler优先级更高!
*/
@ExceptionHandler(Exception.class)
public Object handlerException(Exception e){
return e.getMessage();
}
}
8.2.2. @ComponentScan注解扫描需要加上异常类所在的包
九、拦截器
9.1. 过滤器和拦截器的区别:
- 作用范围:
如上图所示,过滤器的拦截范围是请求还在springmvc外部时,而拦截器HandlerInterceptor是在springmvc内部作用,具体是在调用Handler之前和之后,还有在总体处理完毕最后。也就是过滤器能够拦截到的是整个项目,拦截器拦截是springmvc负责的请求。
- 适用项目:
过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。而拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。
- 拦截请求类型:
过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。例如:直接请求直接访问静态资源拦截器就不拦截了。
- 注入情况Bean不同:
拦截器加载的时间点在springcontext之前,而Bean又是由spring进行管理。所以,在实现了过滤器接口的类中去使用依赖注入是无效的,会有空指针异常。
9.2. 代码案例:
9.2.1. 新建拦截器类
public class MyInterceptor implements HandlerInterceptor {
//到达目标方法前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("request = " + request + ", response = " + response + ", handler = " + handler);
System.out.println("Process01Interceptor.preHandle");
// 返回true:放行
// 返回false:不放行
return true;
}
//到达目标方法后
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", modelAndView = " + modelAndView);
System.out.println("Process01Interceptor.postHandle"); }
// 渲染视图之后执行(最后),一定执行!
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", ex = " + ex);
System.out.println("Process01Interceptor.afterCompletion"); }
}
9.2.2. MvcConfig类中实现接口WebMvcConfigurer(之前已经做过)
重写方法
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());}
本章结束,下章转至ssm框架介绍