分层模型与MVC

Java EE 分层模型

Java EE(Java Platform, Enterprise Edition)分层模型是一个典型的企业级应用架构模型,通常分为以下几个层次:

  1. 客户端层(Client Layer)
    • 职责:负责与用户进行交互,通过浏览器、桌面应用程序或移动设备向用户展示界面,并接受用户输入。
    • 示例:Web 浏览器、JavaFX 应用、Android 应用等。
  2. 表示层(Presentation Layer)
    • 职责:处理用户请求,将请求转发给业务逻辑层并返回结果给客户端。此层主要负责显示和处理与用户交互的内容。
    • 技术:Servlets、JSP (JavaServer Pages)、JSF (JavaServer Faces)等。
    • 示例:用户登录页面、数据展示页面等。
  3. 业务逻辑层(Business Logic Layer / Application Layer)
    • 职责:处理核心业务逻辑,包括业务规则、数据处理等。它接收来自表示层的请求,进行逻辑处理后将结果返回给表示层。
    • 技术:EJB (Enterprise JavaBeans)、POJOs (Plain Old Java Objects)、Spring Framework等。
    • 示例:订单处理系统、用户认证系统等。
  4. 数据访问层(Data Access Layer / Persistence Layer)
    • 职责:负责与数据库交互,执行数据的持久化操作。它提供了访问和操作数据库的方法,屏蔽了数据库的具体实现细节。
    • 技术:JPA (Java Persistence API)、Hibernate、JDBC (Java Database Connectivity)等。
    • 示例:数据库连接池管理、数据查询和存储等。
  5. 企业信息系统层(Enterprise Information System Layer / Integration Layer)
    • 职责:与外部系统和服务进行交互,如消息队列、外部 Web 服务、ERP 系统等。它主要负责系统间的集成和数据交换。
    • 技术:JMS (Java Message Service)、JCA (Java EE Connector Architecture)、Web Services (SOAP/REST)等。
    • 示例:与第三方支付系统的集成、使用消息队列处理异步任务等。

Java EE 分层模型图解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+-------------------------------------+
| 客户端层 (Client Layer) |
+-------------------------------------+
|
v
+-------------------------------------+
| 表示层 (Presentation Layer) |
+-------------------------------------+
|
v
+-------------------------------------+
| 业务逻辑层 (Business Layer) |
+-------------------------------------+
|
v
+-------------------------------------+
| 数据访问层 (Data Access Layer) |
+-------------------------------------+
|
v
+-------------------------------------+
| 企业信息系统层 (Enterprise Layer) |
+-------------------------------------+

关键特点

  • 松耦合:各层之间通过接口或契约进行交互,降低了各层之间的依赖性,方便系统的扩展和维护。
  • 可重用性:每一层的组件可以独立开发和测试,增加了代码的可重用性。
  • 分离关注点:将不同的功能和职责分离到不同的层次,简化了开发过程,使得每个层次关注特定的问题。

这种分层架构模型使得 Java EE 应用具有良好的可扩展性、维护性和可靠性,是企业级应用开发中的标准架构。

MVC模式和MVC框架

在对Java代码进行审计的时候,基本遵从的逻辑是从数据的输入,数据的处理方式,结果的输出来审计是否存在可利用的漏洞点,此流程也基本遵循MVC的思想。MVC的三个核心分别是模型,视图,控制器,分离的思想更有利于在审计的时候更快速准确的找到问题点,无需在意其他不相关的问题。

JavaMVC模式

MVC概述

MVC中M(Model)是指数据模型,V(View)是指用户视图,C(Controller)是控制器, 它强调将应用程序分为三部分。

  1. Model(模型)
  • 表示应用程序的数据或业务逻辑。
  • 负责与数据库等数据源交互,处理数据的创建、读取、更新和删除(CRUD 操作)。
  • 与视图和控制器解耦,专注于处理数据和业务规则。
  1. View(视图)
  • 负责向用户展示数据,通常是用户界面(UI)。
  • 从模型中获取数据,并以合适的形式展示给用户,如网页、图形界面等。
  • 不包含业务逻辑,只负责展示内容。
  1. Controller(控制器)
  • 充当模型和视图之间的中介。
  • 负责处理用户的请求,调用模型中的数据处理方法,并将数据传递给视图进行展示。
  • 控制器接收来自视图的用户输入,更新模型并更新视图。

MVC工作流程

基本的工作流程为Controller层接受用户的请求,并调用对应的Model来进行处理,由Model使用逻辑处理用户的请求并返回数据给View层,再由View层将最后的结果呈现给用户。

MVC模式使得视图层和业务层分离,再当业务的流程或是业务规则发生变化时,仅需要对Model层进行修改即可,使得Web应用更易于维护和修改。

JavaMVC框架

常见的 Java MVC 框架有以下几种,它们在功能、易用性、扩展性和性能方面各有特点:

Spring MVC

特点

  • 广泛使用:Spring MVC 是 Java 中最受欢迎的 MVC 框架之一,属于 Spring 框架的一部分。它提供了构建企业级 web 应用的全面解决方案。
  • 依赖注入:通过 Spring 的依赖注入,开发者可以轻松管理对象的生命周期,减少了代码的耦合。
  • 灵活的视图解析:支持多种视图技术,如 JSP、Thymeleaf、FreeMarker 等。
  • 强大的 REST 支持:Spring MVC 为构建 RESTful API 提供了强大而灵活的支持,便于开发现代 web 应用。
  • 集成性好:与 Spring 生态系统(如 Spring Boot、Spring Security 等)紧密集成,开发效率高。

适用场景:需要构建复杂的企业级应用,要求高扩展性和性能。

Struts 2

特点

  • 开源框架:Struts 是 Apache 基金会维护的一个老牌 MVC 框架,基于 Servlet 和 JSP 技术。
  • 面向请求:以请求为中心,框架通过 Action 类和 XML 配置文件来映射请求。
  • 易扩展:提供了强大的插件机制,可以根据需求自定义功能。
  • 灵活的表单处理:提供了一些自动化的数据转换和验证机制,简化了表单数据处理。

适用场景:适合构建中型企业应用,支持面向表单和请求的开发模式。

JSF (JavaServer Faces)

特点

  • 基于组件的 UI 框架:JSF 主要是一个用户界面框架,侧重于组件化开发。开发者可以使用现成的 UI 组件(如按钮、输入框等)构建页面。
  • 内置生命周期管理:JSF 内置了完整的请求/响应生命周期管理,包括验证、数据转换、模型更新等。
  • 可扩展性强:通过自定义组件库,开发者可以扩展 JSF 的 UI 组件。
  • 与 Java EE 紧密集成:作为 Java EE 标准的一部分,JSF 与其他 Java EE 技术(如 EJB、JPA)紧密结合。

适用场景:适合需要大量 UI 组件的应用,常用于构建基于组件的企业级应用。

JavaWeb核心技术

Servlet

Servlet运行在服务器上,负责接收客户端(如浏览器)的请求,处理请求,然后生成响应并返回给客户端。它的主要任务是在服务器和客户端之间进行通信和数据处理,通常用于处理动态网页内容(如用户登录、数据提交、处理表单等)。

Servlet工作流程

  1. 客户端请求:用户在浏览器中输入网址,或通过表单提交数据,发送请求到服务器。
  2. 服务器调用 Servlet:服务器接收到请求后,将请求转发给相应的 Servlet 进行处理。
  3. Servlet 处理请求:Servlet 根据请求的内容进行处理(如访问数据库、计算结果、生成动态内容等)。
  4. Servlet 生成响应:处理完请求后,Servlet 会生成 HTTP 响应,并将结果返回给客户端(如返回 HTML 页面或 JSON 数据)。
  5. 客户端接收响应:浏览器接收到服务器返回的响应,展示结果给用户。

生命周期

  1. 初始化(init)
  • 当客户端第一次请求 Servlet 时,服务器会加载并初始化该 Servlet。这个初始化阶段会调用 init() 方法,执行一次,主要用于准备资源(如数据库连接)。
  1. 处理请求(service)
  • 每当有客户端请求该 Servlet 时,服务器会调用 service() 方法,处理请求并生成响应。通常,这个方法会根据请求的类型调用 doGet()doPost() 等方法。
  1. 销毁(destroy)
  • 当服务器关闭或需要释放资源时,会调用 destroy() 方法,销毁 Servlet,释放占用的资源(如关闭数据库连接)。

主要方法

Servlet 是通过实现 javax.servlet.Servlet 接口来工作的,但通常开发者会继承 HttpServlet 类,专注于处理 HTTP 请求。常用的方法有:

  • **init()**:Servlet 初始化时调用,用于准备资源。
  • **service()**:每次请求都会调用,负责处理请求,通常开发者不会直接使用该方法,而是通过 doGet()doPost() 等子方法处理。
  • **doGet()**:处理 GET 请求(例如从浏览器获取数据)。
  • **doPost()**:处理 POST 请求(例如表单提交)。
  • **destroy()**:Servlet 被销毁时调用,清理资源。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应的内容类型
resp.setContentType("text/html");

// 生成响应内容
resp.getWriter().println("<html><body>");
resp.getWriter().println("<h1>Hello, Servlet!</h1>");
resp.getWriter().println("</body></html>");
}
}

配置方法

基于web.xml

web.xml 是 Java Web 应用的部署描述文件,位于应用的 WEB-INF 目录下。通过编辑 web.xml,你可以为 Servlet 进行配置,包括定义 Servlet 名称、映射 URL 路径等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

<!-- 定义一个 Servlet -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
</servlet>

<!-- 定义 Servlet 的 URL 映射 -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

</web-app>

配置说明:

  • **<servlet>**** 标签**:定义 Servlet 名称和类路径,<servlet-name> 用来命名该 Servlet,<servlet-class> 指向实际的 Servlet 类(即实现业务逻辑的 Java 类)。
  • **<servlet-mapping>**** 标签**:定义 URL 路径和 Servlet 名称之间的映射关系,当客户端访问 /hello 路径时,服务器会调用 HelloServlet 进行处理。

过这种方式,可以在 web.xml 中配置多个 Servlet,并为它们设置不同的 URL 映射。

基于注释

Servlet 3.0 开始,Java 支持通过注解来配置 Servlet,而不需要在 web.xml 中手动编写配置。这种方式更加简洁,尤其适用于较小的应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "HelloServlet", urlPatterns = {"/hello"})
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.getWriter().println("<h1>Hello, Servlet!</h1>");
}
}


配置说明:

  • **@WebServlet**** 注解**:通过这个注解,直接在 Servlet 类上配置名称和 URL 映射。name 是 Servlet 的名称,urlPatterns 定义了该 Servlet 处理的 URL(这里是 /hello)。
  • 这样做不需要在 web.xml 中添加任何配置,Servlet 会自动根据注解进行注册。

Filter

Filter 的主要作用是对请求和响应进行某种形式的处理,类似于在请求到达目标 Servlet 或 JSP 之前增加一个“过滤”步骤。它能够:

  1. 过滤请求:在请求到达 Servlet 前对请求信息进行检查或修改,如验证用户权限、设置编码格式等。
  2. 过滤响应:在服务器生成响应后对响应信息进行处理,如压缩数据、修改响应内容等。
  3. 链式处理:多个过滤器可以串联在一起,形成一个过滤链,每个过滤器依次对请求和响应进行处理。

Filter工作流程

可以在请求到达目标前资源前进行预处理,也可以在相应返回客户端前进行后处理。多个Filter可以进行串联使用,按照配置的顺序依次处理请求和响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1. 客户端发起请求
|
v
2. 服务器检查 Filter 并开始执行
|
v
3. Filter 1 预处理请求
|
v
4. Filter 2 预处理请求
|
v
5. 请求传递到目标 Servlet 或 JSP
|
v
6. Servlet 处理业务逻辑,生成响应
|
v
7. Filter 2 后处理响应
|
v
8. Filter 1 后处理响应
|
v
9. 服务器将响应返回给客户端

生命周期

Filter 的生命周期与 Servlet 类似,主要包括三个阶段:

  1. 初始化(init):Filter 被加载时调用,只执行一次,通常在这个阶段进行一些资源初始化的操作。
  2. 过滤请求和响应(doFilter):每当有请求到来时,Filter 会通过 doFilter() 方法对请求和响应进行处理。
  3. 销毁(destroy):Filter 被移除或服务器关闭时调用,通常在这个阶段释放资源。

代码示例

Filter 是通过实现 javax.servlet.Filter 接口来实现的。需要重写其中的三个方法:init()doFilter()destroy()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class LoggingFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 过滤器初始化
System.out.println("LoggingFilter initialized");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 过滤请求,记录请求的URL
HttpServletRequest httpRequest = (HttpServletRequest) request;
String url = httpRequest.getRequestURI();
System.out.println("Request URL: " + url);

// 继续处理请求,传递给下一个 Filter 或目标资源(Servlet、JSP)
chain.doFilter(request, response);
}

@Override
public void destroy() {
// 释放资源
System.out.println("LoggingFilter destroyed");
}
}

配置方法

基于web.xml

1
2
3
4
5
6
7
8
9
<filter>
<filter-name>LoggingFilter</filter-name>
<filter-class>com.example.LoggingFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>LoggingFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 这个 Filter 应用于所有 URL -->
</filter-mapping>

基于注释

从 Servlet 3.0 开始,Filter 可以使用注解进行配置,代码会更加简洁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*") // 应用于所有请求
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoggingFilter initialized");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("LoggingFilter: Request received");
chain.doFilter(request, response);
}

@Override
public void destroy() {
System.out.println("LoggingFilter destroyed");
}
}

Listener

Listener 的作用

Listener 主要用于在特定的生命周期事件发生时执行某些操作。常见的应用场景包括:

  1. 监听 Web 应用启动和关闭:在 Web 应用启动时初始化资源(如数据库连接),在应用关闭时释放资源。
  2. 监听用户请求的创建和销毁:在每个请求到达或结束时进行日志记录、统计访问量等。
  3. 监听会话的创建和销毁:在用户会话创建时记录用户登录信息,销毁时清理会话相关数据。
  4. 监听属性的变化:当某个对象的属性(如会话或应用中的变量)被添加、修改或删除时,执行相应的操作。

Listener 工作流程

  1. 应用启动/关闭ServletContextListener 监听应用的启动和关闭事件。
  2. 会话创建/销毁HttpSessionListener 监听每个用户会话的创建和销毁,通常用于登录用户的跟踪。
  3. 请求开始/结束ServletRequestListener 监听每个请求的到达和结束,常用于日志记录和统计请求处理时间。
  4. 属性变化:属性监听器会在对象的属性变化时(添加、修改或删除)执行对应的操作。

常见的 Listener 类型

在 Java Web 中,主要有三类监听器,分别对应不同的 Web 对象的生命周期或属性变化:

  1. ServletContextListener(监听 Web 应用的生命周期)
  • 监听整个 Web 应用的启动和关闭。
  • 常用于在应用启动时执行初始化工作,如加载配置文件、初始化数据库连接等。
  • 在应用关闭时进行资源的释放和清理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Web 应用启动");
// 在这里进行初始化工作
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Web 应用关闭");
// 在这里释放资源
}
}

  1. HttpSessionListener(监听会话的创建和销毁)
  • 监听用户会话的创建和销毁事件。
  • 常用于统计在线用户数量、记录用户登录信息等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MySessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("会话创建");
// 执行会话创建时的逻辑
}

@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("会话销毁");
// 执行会话销毁时的逻辑
}
}

  1. ServletRequestListener(监听请求的创建和销毁)
  • 监听每个请求的开始和结束。
  • 常用于记录日志、统计请求的处理时间、处理请求前后的数据等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyRequestListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("请求创建");
// 处理请求初始化时的逻辑
}

@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("请求销毁");
// 处理请求销毁时的逻辑
}
}

属性监听器

属性监听器主要用于监听对象中属性的变化,如当属性被添加、移除或修改时触发。常见的属性监听器有:

  1. HttpSessionAttributeListener:监听会话属性的添加、修改和删除。
  2. ServletContextAttributeListener:监听应用范围属性的添加、修改和删除。
  3. ServletRequestAttributeListener:监听请求属性的添加、修改和删除。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MySessionAttributeListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
System.out.println("属性添加:" + event.getName());
}

@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("属性移除:" + event.getName());
}

@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
System.out.println("属性修改:" + event.getName());
}
}

Listener 的配置

Listener 可以通过两种方式配置:**web.xml** 文件中配置使用注解配置

基于web.xml

1
2
3
4
<listener>
<listener-class>com.example.MyContextListener</listener-class>
</listener>

基于注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import javax.servlet.annotation.WebListener;

@WebListener
public class MyContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Web 应用启动");
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Web 应用关闭");
}
}


分层模型与MVC
https://ox130e07d.github.io/2024/09/10/分层模型与MVC/
作者
Noah
发布于
2024年9月10日
许可协议