2024/9/28

前端控制器,是整体流程控制的中心,由它调用其他组件处理用户请求,降低耦合性
DispatcherServlet是Spring MVC框架的核心组件,负责处理所有的HTTP请求和响应。以下是对它的具体介绍:
1. **核心功能**
- **接收请求**:DispatcherServlet作为前端控制器,它接收所有传输到Web应用的HTTP请求[^1^]。
- **分发请求**:它通过HandlerMapping来匹配请求URL和相应的处理器(Controller),并将请求传递给该处理器进行处理[^5^]。
- **返回响应**:在处理器处理完请求后,DispatcherServlet将响应返回给客户端[^5^]。
- **数据绑定**:它还负责将模型数据绑定到视图中,以便在返回响应时将数据呈现给用户[^5^]。
2. **工作流程**
- **初始化过程**:当Tomcat启动时,会实例化DispatcherServlet并调用其初始化方法进行初始化,包括加载web.xml中的初始化参数,建立WebApplicationContext,以及进行组件的初始化[^2^]。
- **请求处理**:客户端发出请求后,如果匹配DispatcherServlet在web.xml中配置的映射路径,Tomcat就将请求转交给DispatcherServlet处理[^2^]。
- **执行流程**:DispatcherServlet从容器中取出所有HandlerMapping实例,每个HandlerMapping会根据请求信息找到处理该请求的Handler,并将其与一堆HandlerInterceptor封装成一个HandlerExecutionChain对象。然后,DispatcherServlet取出HandlerAdapter组件,根据已经找到的Handler,再从所有HandlerAdapter中找到可以处理该Handler的HandlerAdapter对象。最后,利用ViewResolver将ModelAndView或是Exception解析成View,然后View会调用render()方法再根据ModelAndView中的数据渲染出页面[^2^]。
3. **集成方式**
- **注解驱动开发**:Spring MVC支持注解驱动开发,这意味着可以通过注解来标识控制器、请求映射和参数绑定等。例如,注解可以标识一个类为控制器,注解可以标识一个方法为处理特定URL请求的处理器[^5^]。
- **拦截器集成**:DispatcherServlet还集成了拦截器的功能,拦截器可以在请求被分发到处理器之前或之后执行特定的逻辑[^5^]。
总的来说,DispatcherServlet是Spring MVC框架的核心组件,它负责接收和处理所有的HTTP请求和响应,通过HandlerMapping和HandlerAdapter将请求分发给相应的处理器,并通过ViewResolver将处理结果转换为视图返回给客户端。
请求响应:
·请求(HttpServletRequest):获取请求数据
·响应(HttpServletResponse):设置响应数据
·BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端 如京东、淘宝、天猫、唯品会
·CS架构:Client/Server,客户端/服务器架构模式 (开发、维护麻烦 体验好)如微信、百度网盘、企业微信、TLIAS客户端
一、请求
(一)Postman
Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件
作用:常用于进行接口测试
(此外,还有Apipost、Apifox)
(二)简单参数
1.原始方式
在原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取

2.SpringBoot方式
简单参数:参数名与形参变量名相同,定义形参即可接收参数

3.@RequestParam注解
·方法形参名称与请求参数名称不匹配,通过该注解完成映射
·该注解的required属性默认是true,代表请求参数必须传递
(三)实体参数
1.简单实体对象
请求参数名与形参对象属性名相同,定义POJO接收即可

首先:

其次:

2.复杂实体对象
请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数

首先:

其次:

(四)数组集合参数
1.数组参数
请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数


实例:

2.集合参数
请求参数名与形参集合名称相同且请求参数为多个,@RequestParam绑定参数关系
(实体类里含有一个hobby数组)

实例:

(五)日期参数
日期参数:使用@DateTimeFormat注解完成日期参数格式转换

实例:

(六)Json参数
JSON参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody标识

raw用于发送原始的,未经处理的,可以是JSON格式的
json就是前后端进行数据交互的一种数据格式,使用键值对的形式表示数据,键是字符串,值可以是字符串,数字,布尔值,对象,数组,null。他支持嵌套和层次结构,可以表示复杂的数据关系,由一对花括号包裹。他在前后端数据交互和API接口设计中应用,易于解析和生成,并且与多种语言兼容。json里面没有列表,只有对象和对象数组。
(七)路径参数
路径参数:通过请求URL直接传递参数,使用{...}来标识该路径参数,需要使用@PathVariable获取路径参数

二、响应
(一)@ResponseBody

@ResponseBody:
·类型:方法注解、类注解
·位置:Controller方法/类上
·作用:将方法返回值直接响应,如果返回值类型是 实体类对象 / 集合,将会转换为JSON格式响应
·说明:@RestControoler = @Controller + @ResponseBody
(二)统一响应结果
不便管理

统一响应结果:
Result(code、msg、data)

具体代码实现:
pojo中,Result.java


@override 是Java中的一个注解,用于指示某个方法是重写了父类中的方法。当子类中的方法使用了@Override注解时,编译器会检查该方法是否正确地重写了父类中的同名方法。如果没有正确重写(例如方法签名不匹配),编译器会报错。使用@Override注解可以提高代码的可读性和减少错误。
RestControoler.java

(三)案例
获取员工数据,返回统一响应结果,在页面渲染展示
步骤:
·在pom.xml文件中,引入dome4j的依赖,用于解析XML文件
·引入资料中提供的解析XML的工具类XMLParserUtils、对应的实体类Emp、XML文件emp.xml
·引入资料中提供的静态页面文件,放在resources下的static目录下
·编写Controller程序,处理请求,响应数据
*SpringBoot项目的静态资源(html,css,js等前端资源)默认存放目录为:classpath:/static、classpath:/public、classpath:/resources
(解释:
(1)引入实体类Emp,用来封装XML解析的结果
(2)工具类中的parse方法,指定所解析的文件,解析的结果在哪个类中封装,parse方法使用dom4j相关的API对文件进行解析,解析完了,将数据封装在List<T>集合中,集合的范型就是我们传递的这个类型)
(3)dom4j把数据进行转换处理,然后再加载
*DOM4J是一个开源的Java XML解析包,用于处理XML、XPath和XSLT。
代码书写板块
1.加载并解析emp.xml
通过类加载器来加载一个 XML 文件,并解析该文件到一个 `Emp` 类的列表中。

String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
·Classcoader:类加载器是一个负责加载类的对象,类加载器还负责定位资源·this.getClass().getClassLoader(): 获取当前类的类加载器。
·getResource("emp.xml"): 通过类加载器查找资源文件(`emp.xml`),返回一个 `URL` 对象。
·getFile():则是 `URL` 类的方法,用来获取资源文件的文件路径。
接下来:
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
这行代码调用了 `XmlParserUtils.parse` 方法,传入了文件路径和 `Emp.class`。
Emp.class:是反射机制中 `Class` 类的一个对象,表示 `Emp` 类的类型。
尽管 `Emp.class` 是反射机制的一部分,但这个代码段并没有真正使用反射的动态特性,例如运行时获取方法、构造方法或字段等。这里 `Emp.class` 只是用来告诉 `XmlParserUtils` 方法要将 XML 文件解析成 `Emp` 类型的对象。
·parse方法的作用是解析 XML 文件,并根据传入的 Class 类型(这里是 Emp.class)将 XML 文件中的数据转换成该类的实例。
2.对数据进行转换处理

3.响应数据

(展示如下)

复用性差,难以维护,于是:
三、分层解耦
(一)三层架构
(单一职责原则)

·controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据
·service:业务逻辑层,处理具体的业务逻辑
·dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查
对上面员工案例的改写过程:
1.在dao中创建interface接口
Dao为Mapper层;数据访问可能是,文件,数据库别人提供的接口获取到的数据,实现的方式很多,为了灵活的切换这些实现,可以通过面向接口的方式进行编程。面向接口的设计原则,增强程序的灵活性。创建接口是为了可以有多种实现,这里的接口代表xml文档的数据处理功能。(面向接口编程,可扩展性好,可以研究设计模式的)
因此,在编写Dao的具体实现之前,先定义一个Dao的接口来增强程序的灵活性和拓展性。即多态的思想。(但是在实际情况下数据是存储在数据库中)
(1)在dao文件中,创建interface接口(EmpDao.java)。列表数据返回的list集合,也就是EmpController.java中的List<Emp>,如图:

(2)接口书写如下:
方法名为listEmp(),用来加载员工数据

2.编写Dao层的代码
(注:这块讲的是类实现接口,重写方法,在实际中的应用)
(1)先创建一个接口限制方法名和返回结果,具体从数据库还是文件取从具体继承的类中实现。
接口多态性,empdao接口只关心获取到的数据不关心怎样获取,emdaoA实现类处理xml数据,而不是别的数据库之类的。
(2)在dao包下,创建一个实现类,实现类放在impl包下,名为EmpDaoA>.java,让该类实现一个接口EmpDao,并且实现其中的方法(快捷键ctrl+回车)

3.编写Service层的代码
(1)与Dao模式类似,为了增强灵活性,创建Service层的接口EmpService,Service中,也需要定义一个方法,用来获取员工列表数据:

(2)编写定义Service的实现类,同样创建impl包并创建EmpServiceA.java中,再让该类实现一个接口EmpService,然后实现其中的方法,处理的数据是这一部分:

复制过来,并改进,在service中调用dao,service中要想调用Dao,就要创建dao的对象,(多态的应用),采用面向接口的方式编程,那么就声明一个接口类型empDao,然后new一个EmpDaoA的实现类:

最后将转换处理后的结果返回
4.编写controller层的代码
(仅负责接收请求,响应数据,不负责逻辑处理)
在controller中,需要调用service来获取数据,然后再响应数据。先定义一个service的对象empService(面向接口编程),然后new一个EmpServiceA。接下来需要调用service获取数据

总结:

(二)分层解耦
1.内聚
软件中各个功能模块内部的功能联系
2.耦合
衡量软件中各个层 / 模块之间的依赖、关联的程度
3.软件设计原则
高内聚低耦合,一般指功能内聚和数据耦合。所以不建议创建对象,建议接口。为了继续降低耦合,于是控制反转,依赖注入

(三)IOC&DI入门
IOC是spring框架的第一大核心
解耦代码实现步骤:
1.Service层及Dao层的实现类,交给IOC容器管理
2.为Controller及Service注入运行时,依赖的对象
3.运行测试
具体实现:
IOC控制反转和DI依赖注入。
1.交给IOC容器
首先将new对象全部删掉,(然后利用IOC与DI进行解耦操作),为了将Dao和Service实现类交给IOC,成为IOC容器中的Bean。(Component注解可以有参数,默认是实现类的类名,首字母小写,若接口有多个实现类,可以在依赖注入时用注解@Autowired的参数指定@Component对应的实现类)于是加上注解@Component,完成控制反转操作。
例如:

2.注入运行时依赖的对象
然后需要为Controller和Service注入运行时所需要依赖的对象,Controller程序运行时依赖于EmpService,Service运行时依赖于EmpDao,因此IOC容器需要提供该类型的Bean对象,并赋值给该变量,于是我加上注解@Autowired,完成依赖注入操作。
例如:

(四)IOC详解
IOC,控制反转,将对象的控制权交给IOC容器,由IOC容器来创建和管理这些对象,IOC容器中的对象也称为Bean对象。
1.Bean的声明

注:
·声明Bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写
·使用以上四个注解都可以声明Bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller
在web程序开发中,推荐下面三个,来标注controller,service,dao,而对于component,在项目中某一个类不能归到这三层里面,就可以用它,典型的就是一些工具类。(这三个也是Componeng的衍生注解),因此声明一个Bean可以通过四个注解来声明。(Ctrl+Service注解,即看到其源码,如图:

在IOC中,每一个bean都有一个标识(即名字),在声明Bean时,可以通过注解当中value属性来指定一个Bean的名字,若没有指定(一般不用指定),那么默认为类名+首字母小写,如图:


2.Bean组件扫描
·前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描
·@ComponentScan注解虽然没有显示配置,但是实际上已经包含在了启动类声明注释@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包


也可以直接指定扫描范围:

(五)DI详解
1.Bean注入
·@Autowired注解,默认是按照类型进行,,即要去IOC容器中找这个类型的Bean对象,然后完成注入。如果存在多个相同类型的bean,将会报如下错误:

·解决方案:
·@Primary——设置bean的优先级
·@Autowired + @Qualifier——按照类型注入(首字母小写)
·@Resource(name = "bean的名称")——按照名称注入

2.@Autowired与@Resource区别
·@Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
·@Autowired默认是按照类型注入,而@Resource默认是按照名称注入
四、补充
(一)前端控制器
是整体流程控制的中心,由它调用其他组件处理用户请求,降低耦合性。
DispatcherServlet是Spring MVC框架的核心组件,负责处理所有的HTTP请求和响应。以下是对它的具体介绍:
1. 核心功能
**接收请求**:DispatcherServlet作为前端控制器,它接收所有传输到Web应用的HTTP请求[^1^]。
**分发请求**:它通过HandlerMapping来匹配请求URL和相应的处理器(Controller),并将请求传递给该处理器进行处理[^5^]。
**返回响应**:在处理器处理完请求后,DispatcherServlet将响应返回给客户端[^5^]。
**数据绑定**:它还负责将模型数据绑定到视图中,以便在返回响应时将数据呈现给用户[^5^]。
2. 工作流程
**初始化过程**:当Tomcat启动时,会实例化DispatcherServlet并调用其初始化方法进行初始化,包括加载web.xml中的初始化参数,建立WebApplicationContext,以及进行组件的初始化[^2^]。
**请求处理**:客户端发出请求后,如果匹配DispatcherServlet在web.xml中配置的映射路径,Tomcat就将请求转交给DispatcherServlet处理[^2^]。
**执行流程**:DispatcherServlet从容器中取出所有HandlerMapping实例,每个HandlerMapping会根据请求信息找到处理该请求的Handler,并将其与一堆HandlerInterceptor封装成一个HandlerExecutionChain对象。然后,DispatcherServlet取出HandlerAdapter组件,根据已经找到的Handler,再从所有HandlerAdapter中找到可以处理该Handler的HandlerAdapter对象。最后,利用ViewResolver将ModelAndView或是Exception解析成View,然后View会调用render()方法再根据ModelAndView中的数据渲染出页面[^2^]。
3. 集成方式
**注解驱动开发**:Spring MVC支持注解驱动开发,这意味着可以通过注解来标识控制器、请求映射和参数绑定等。例如,注解可以标识一个类为控制器,注解可以标识一个方法为处理特定URL请求的处理器[^5^]。
**拦截器集成**:DispatcherServlet还集成了拦截器的功能,拦截器可以在请求被分发到处理器之前或之后执行特定的逻辑[^5^]。
总的来说,DispatcherServlet是Spring MVC框架的核心组件,它负责接收和处理所有的HTTP请求和响应,通过HandlerMapping和HandlerAdapter将请求分发给相应的处理器,并通过ViewResolver将处理结果转换为视图返回给客户端。
(二)反射1
案例部分补充
“组装数据,利用反射构建构造器,获取指定形参类型的构造器,设置强制反射”
1.组装数据
在计算机科学和编程中,“组装数据”通常指的是将多个数据片段或数据结构组合成一个更复杂或完整的数据结构。这可以涉及将不同类型的数据(如字符串、数字、对象等)合并到一起,或者将多个数据源的数据整合到一个统一的格式中。在前端开发中,这可能是指将来自不同API端点的数据组合成一个单一的数据集,以便在用户界面中显示。
2.利用反射构建构造器
反射是Java语言中的一个特性,它允许程序在运行时检查和修改自己的行为。通过反射,你可以动态地创建类的对象实例,调用方法,访问字段,以及获取关于类的元信息(如构造器、方法和字段)。
构建构造器通常是指使用反射来动态地创建一个类的实例。这涉及到找到类的正确构造器(Constructor),然后使用它来创建一个新的实例。
3.获取指定形参类型的构造器
在Java中,每个构造器都有一个参数列表,称为形参列表。当你使用反射来创建一个类的实例时,你需要找到与你想要传递的参数匹配的构造器。这通常是通过`Class`类的`getConstructor`方法来完成的,该方法接受一个`Class<?>... parameterTypes`参数数组,用于指定构造器的参数类型。
例如,如果你有一个类`MyClass`,它有一个接受两个参数的构造器,你可以这样获取它的构造器:
Constructor<MyClass> constructor = MyClass.class.getConstructor(String.class, int.class);
4.设置强制反射
这个表述可能需要一些澄清,因为在标准的Java反射API中并没有直接称为“强制反射”的概念。不过,我猜测这里可能指的是在进行反射操作时,忽略Java的访问控制检查(如private、protected修饰符),从而能够访问和修改私有或受保护的成员。
在Java反射中,可以通过调用`setAccessible(true)`方法来实现这一点。这个方法使得反射操作可以绕过Java的访问控制,从而可以访问私有或受保护的成员。例如:
Field privateField = MyClass.class.getDeclaredField("privateFieldName");
privateField.setAccessible(true);
在上面的代码中,我们首先获取了`MyClass`类的私有字段`privateFieldName`的`Field`对象,然后通过调用`setAccessible(true)`方法来允许对这个私有字段的访问。
请注意,使用反射来访问私有成员是一种强大的功能,但也应该谨慎使用,因为它可能会破坏封装性并导致代码难以维护。
(三)反射2
在Spring Boot中,反射通常用于实现一些高级功能和动态行为,如依赖注入、AOP(面向切面编程)、事件处理等。以下是几个常见的应用场景:
1. 依赖注入(DI)
Spring的核心功能之一是依赖注入,它使用反射来动态创建和管理Bean的生命周期。通过注解(如`@Autowired`、`@Component`、`@Service`等),Spring可以在运行时自动装配依赖关系。
@Service
public class MyService {
// Some methods...
}
@RestController
public class MyController {
@Autowired
private MyService myService;
// Some methods...
2. 面向切面编程(AOP)
Spring AOP使用反射来实现横切关注点(如日志记录、事务管理等)。通过定义切面(Aspect),你可以在方法执行前后插入额外的逻辑。
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.MyService.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Method " + joinPoint.getSignature() + " is about to be called");
}
}
3. 事件处理
Spring的事件处理机制允许你在应用程序中的不同部分之间进行解耦通信。通过发布和监听事件,可以实现松耦合的设计。```java
// 定义一个事件
public class CustomEvent extends ApplicationEvent {
public CustomEvent(Object source) {
super(source);
}
}
// 发布事件
@Component
public class MyService {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void doSomething() {
// Do something...
applicationEventPublisher.publishEvent(new CustomEvent(this));
}
}
// 监听事件
@Component
public class MyListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Received custom event - " + event.toString());
}
}
4. 动态加载Bean
在某些情况下,你可能需要在运行时动态加载和实例化Bean。这可以通过`ApplicationContext`来实现。
@Autowired
private ApplicationContext applicationContext;
public void loadBeanDynamically(String beanName) {
MyInterface myBean = (MyInterface) applicationContext.getBean(beanName);
myBean.someMethod();
}
5. 条件化Bean
Spring允许你根据不同的条件(如操作系统、环境变量等)来创建不同的Bean。这可以通过`@Conditional`注解或`Condition`接口来实现。```java
@Configuration
public class MyConfiguration {
@Bean
@Conditional(MyCondition.class)
public MyService myService() {
return new MyServiceImpl1();
}
@Bean
@Conditional(MyOtherCondition.class)
public MyService myService() {
return new MyServiceImpl2();
}
}
6. 使用反射创建对象
虽然Spring本身已经提供了强大的依赖注入机制,但有时你可能需要直接使用反射来创建对象。例如,在编写通用代码或框架时。
public class MyGenericClass<T> {
public T createInstance(String className) throws Exception {
Class<?> clazz = Class.forName(className);
return (T) clazz.getDeclaredConstructor().newInstance();
}
}
**注意事项
尽管反射在Spring应用中非常有用,但它也有一些潜在的缺点,如性能开销和代码可读性问题。因此,在使用反射时应谨慎权衡利弊,确保它是解决特定问题的合适方案。
(四) DOM4J
DOM4J(Document Object Model for Java)是一个易用的、开源的库,专门设计用于在Java平台上处理XML数据。它采用了Java集合框架,并完全支持DOM(文档对象模型)、SAX(简单API用于XML)和JAXP(Java API for XML Processing)。这使得DOM4J成为一个功能强大且灵活的XML解析工具[^1^][^3^]。
DOM4J的主要特点是使用了大量的接口,这些接口定义了XML文档的各种组成部分,如属性、元素、注释等。通过这些接口,用户可以方便地读取、修改和写入XML文档[^5^]。例如,通过`org.dom4j.io.SAXReader`类,用户可以轻松地将XML文件解析为一个`Document`对象,然后通过各种方法操作这个对象,如获取根节点、遍历子节点、添加新节点等[^2^][^4^]。
此外,DOM4J还提供了对XPath的支持,允许用户使用XPath表达式来查询和定位XML文档中的特定节点1。这种功能使得DOM4J在处理复杂XML结构时特别有用。
总的来说,DOM4J是一个功能强大、易于使用的Java XML解析库,适用于需要处理XML数据的各种应用场景。无论是简单的XML读写操作,还是复杂的XPath查询,DOM4J都能提供高效且灵活的解决方案。
(五)parse

在这段代码中,parse 是 XmlParserUtils 类中的一个方法。它的作用是将 emp.xml 文件的内容解析成 Emp 类的对象列表。虽然我们没有看到 XmlParserUtils 类的具体实现,但可以推测它是一个帮助工具类,用来处理 XML 文件的解析。
通常,parse 方法做的工作包括:
- 读取 XML 文件:打开并读取指定的 XML 文件内容。
- 解析 XML 数据:通过某种 XML 解析器(例如 SAX、DOM、或基于注解的 JAXB)将 XML 文件中的数据转换成 Java 对象。
- 将数据映射到 Java 对象:在这个例子中,
Emp.class传递给了parse,说明XmlParserUtils应该会将 XML 文件中的元素或节点映射到Emp类的属性上。也就是说,它会把 XML 文件中的每个<emp>元素映射为一个Emp对象。
&spm=1001.2101.3001.5002&articleId=142618341&d=1&t=3&u=e56cd5300149495288c5f2e774eb2ba2)
865

被折叠的 条评论
为什么被折叠?



