目录

Java Web 技术演进:从 Servlet 到 Spring MVC 与阿里 ROP 全面对比

全面对比 Servlet、Struts2、Spring MVC 与阿里 ROP 的技术演进

Java Web 开发技术经历了从传统的 Servlet/JSP 到 MVC 框架,再到 RESTful 服务框架的演进。本文深入对比 Tomcat Servlet、Struts2、Spring MVC 和阿里 ROP 四种技术方案。

一、技术概览

1.1 四种技术定位

技术类型出现时间维护状态定位
Servlet/JSP基础规范1997年活跃(Jakarta EE)Java Web 基石
Struts2MVC 框架2007年维护中(Apache)企业级 MVC 框架
Spring MVCMVC 框架2005年活跃(Spring)现代化 MVC 框架
阿里 ROPREST 框架2012年停止维护开放平台接口框架

1.2 技术演进路线

1997年          2005年           2007年           2012年           2020年
  │               │                │                │                │
  ▼               ▼                ▼                ▼                ▼
Servlet ──────► Spring ───────► Struts2 ───────► 阿里ROP ───────► Spring Boot
  │              MVC                              (REST)           (自动配置)
  │                                                │
  ▼                                                ▼
JSP                                          Spring WebFlux
(模板引擎)                                    (响应式编程)

二、Tomcat Servlet(规范基石)

2.1 核心概念

Servlet 是 Java EE 规范的核心,定义了服务端处理 HTTP 请求的标准接口。

┌─────────────────────────────────────────┐
│              HTTP Request                │
└─────────────────┬───────────────────────┘
┌─────────────────────────────────────────┐
│           Servlet Container              │
│  ┌─────────────────────────────────┐    │
│  │  ServletContext(全局上下文)    │    │
│  │  ┌─────────────────────────┐    │    │
│  │  │   HttpServletRequest    │    │    │
│  │  │   HttpServletResponse   │    │    │
│  │  └───────────┬─────────────┘    │    │
│  │              │                  │    │
│  │  ┌───────────▼───────────┐      │    │
│  │  │     HttpServlet       │      │    │
│  │  │  ┌─────────────────┐  │      │    │
│  │  │  │ doGet()         │  │      │    │
│  │  │  │ doPost()        │  │      │    │
│  │  │  │ service()       │  │      │    │
│  │  │  └─────────────────┘  │      │    │
│  │  └───────────────────────┘      │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

2.2 基础代码示例

// 传统 Servlet 写法
@WebServlet(name = "UserServlet", urlPatterns = "/user")
public class UserServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        // 1. 获取参数
        String userId = req.getParameter("id");
        
        // 2. 调用业务逻辑
        UserService service = new UserService();
        User user = service.findById(userId);
        
        // 3. 设置响应
        resp.setContentType("application/json");
        resp.setCharacterEncoding("UTF-8");
        
        // 4. 手动拼接 JSON(痛苦!)
        PrintWriter out = resp.getWriter();
        out.print("{\"id\":\"" + user.getId() + "\",\"name\":\"" + user.getName() + "\"}");
        out.flush();
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        // 1. 获取请求体
        BufferedReader reader = req.getReader();
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        
        // 2. 手动解析 JSON(痛苦!)
        String json = sb.toString();
        // ... 复杂的解析逻辑
        
        // 3. 调用业务逻辑
        // ...
        
        // 4. 返回响应
        resp.setStatus(HttpServletResponse.SC_CREATED);
    }
}

2.3 Servlet 过滤器链

// 字符编码过滤器
@WebFilter(filterName = "EncodingFilter", urlPatterns = "/*")
public class EncodingFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        // 继续下一个过滤器
        chain.doFilter(request, response);
    }
}

// 登录验证过滤器
@WebFilter("/admin/*")
public class AuthFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpSession session = request.getSession(false);
        
        if (session == null || session.getAttribute("user") == null) {
            ((HttpServletResponse) resp).sendRedirect("/login");
            return;
        }
        
        chain.doFilter(req, resp);
    }
}

2.4 优缺点分析

优点缺点
规范标准,所有框架底层都基于 Servlet开发效率低,样板代码多
学习成本低,理解 HTTP 处理原理无 MVC 分层,代码耦合严重
性能高(直接操作请求响应)手动处理 JSON/XML 转换
过滤器、监听器机制完善URL 映射配置繁琐
生态成熟(Tomcat/Jetty/Undertow)无依赖注入,需手动管理对象

三、Struts2(企业级 MVC)

3.1 核心架构

Struts2 采用 拦截器栈(Interceptor Stack) 架构,基于过滤器实现。

┌─────────────────────────────────────────┐
           HTTP Request                   
└─────────────────┬───────────────────────┘
                  
┌─────────────────────────────────────────┐
   StrutsPrepareAndExecuteFilter          
           (核心过滤器)                  
└─────────────────┬───────────────────────┘
                  
┌─────────────────────────────────────────┐
      Interceptor Stack(拦截器栈)        
  ┌─────────────────────────────────┐    
    1. ParamsInterceptor                
       参数解析、类型转换                
    2. ValidationInterceptor            
       数据校验                         
    3. FileUploadInterceptor            
       文件上传处理                      
    4. ExceptionMappingInterceptor      
       异常映射                         
  └─────────────────────────────────┘    
└─────────────────┬───────────────────────┘
                  
┌─────────────────────────────────────────┐
         Action(控制器)                 
    execute() / 自定义方法                
└─────────────────┬───────────────────────┘
                  
┌─────────────────────────────────────────┐
         Result(结果处理)               
  ┌──────────┬──────────┬────────────┐   
   dispatcher redirect  stream        
   (JSP)      (重定向)   (文件下载)     
  └──────────┴──────────┴────────────┘   
└─────────────────────────────────────────┘

3.2 代码示例

// Action 类
public class UserAction extends ActionSupport implements ModelDriven<User> {
    
    private User user = new User();
    private List<User> userList;
    private UserService userService = new UserService();
    
    // 模型驱动,自动封装表单数据到 user 对象
    @Override
    public User getModel() {
        return user;
    }
    
    // 查询列表
    public String list() {
        userList = userService.findAll();
        return SUCCESS;  // 对应 struts.xml 中的 result
    }
    
    // 查询详情
    public String detail() {
        user = userService.findById(user.getId());
        if (user == null) {
            return ERROR;
        }
        return SUCCESS;
    }
    
    // 新增用户
    public String save() {
        // 校验(使用 Validation 框架)
        if (user.getName() == null || user.getName().isEmpty()) {
            addFieldError("name", "用户名不能为空");
            return INPUT;
        }
        
        userService.save(user);
        addActionMessage("用户创建成功");
        return SUCCESS;
    }
    
    // 删除用户
    public String delete() {
        userService.delete(user.getId());
        return SUCCESS;
    }
    
    // Getters for JSP
    public List<User> getUserList() {
        return userList;
    }
    
    public User getUser() {
        return user;
    }
}
<!-- struts.xml 配置 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
    <!-- 常量配置 -->
    <constant name="struts.devMode" value="true"/>
    <constant name="struts.action.extension" value="action,do,"/>
    <constant name="struts.objectFactory" value="spring"/>
    
    <!-- 包配置 -->
    <package name="default" namespace="/" extends="struts-default">
        
        <!-- 全局结果 -->
        <global-results>
            <result name="error">/error.jsp</result>
            <result name="login" type="redirect">/login.jsp</result>
        </global-results>
        
        <!-- Action 配置 -->
        <action name="user_*" class="com.example.action.UserAction" method="{1}">
            <result name="success">/WEB-INF/jsp/user/{1}.jsp</result>
            <result name="input">/WEB-INF/jsp/user/form.jsp</result>
            <result name="list">/WEB-INF/jsp/user/list.jsp</result>
            
            <!-- 拦截器配置 -->
            <interceptor-ref name="defaultStack">
                <param name="validation.excludeMethods">list,detail</param>
            </interceptor-ref>
        </action>
        
        <!-- REST 风格配置 -->
        <action name="api/user" class="com.example.action.UserRestAction">
            <result type="json">
                <param name="root">result</param>
            </result>
        </action>
    </package>
</struts>

3.3 OGNL 表达式

Struts2 使用 OGNL(Object-Graph Navigation Language)进行数据绑定。

<!-- JSP 页面使用 OGNL -->
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>

<html>
<head><title>用户列表</title></head>
<body>
    <h1>用户管理</h1>
    
    <!-- 迭代列表 -->
    <table>
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>邮箱</th>
            <th>操作</th>
        </tr>
        <s:iterator value="userList" var="user">
            <tr>
                <td><s:property value="#user.id"/></td>
                <td><s:property value="#user.name"/></td>
                <td><s:property value="#user.email"/></td>
                <td>
                    <a href="user_detail.action?id=<s:property value='#user.id'/>">查看</a>
                    <a href="user_delete.action?id=<s:property value='#user.id'/>">删除</a>
                </td>
            </tr>
        </s:iterator>
    </table>
    
    <!-- 表单 -->
    <s:form action="user_save" method="post">
        <s:textfield name="name" label="用户名" required="true"/>
        <s:password name="password" label="密码"/>
        <s:textfield name="email" label="邮箱"/>
        <s:submit value="保存"/>
    </s:form>
    
    <!-- 显示错误信息 -->
    <s:fielderror/>
    <s:actionmessage/>
</body>
</html>

3.4 优缺点分析

优点缺点
完整的 MVC 分层,职责清晰配置繁琐(XML/注解混合)
强大的拦截器机制OGNL 学习曲线陡峭
内置丰富的标签库历史漏洞较多(需及时更新)
与 Spring 集成良好已被 Spring MVC 取代主流地位
插件丰富(JSON/REST/文件上传)开发效率低于现代框架
Convention over Configuration启动速度较慢

四、Spring MVC(现代标准)

4.1 核心架构

Spring MVC 基于 DispatcherServlet,采用注解驱动开发。

┌─────────────────────────────────────────┐
│           HTTP Request                   │
└─────────────────┬───────────────────────┘
┌─────────────────────────────────────────┐
│       DispatcherServlet                  │
│         (前端控制器)                    │
│  ┌─────────────────────────────────┐    │
│  │    HandlerMapping               │    │
│  │    (URL → Controller 映射)     │    │
│  │  @RequestMapping("/users")      │    │
│  └─────────────────────────────────┘    │
│                  │                      │
│                  ▼                      │
│  ┌─────────────────────────────────┐    │
│  │    HandlerAdapter               │    │
│  │    (调用 Controller 方法)       │    │
│  └─────────────────────────────────┘    │
│                  │                      │
│                  ▼                      │
│  ┌─────────────────────────────────┐    │
│  │    Controller (@Controller)     │    │
│  │    @GetMapping("/{id}")         │    │
│  │    public User get(@PathVariable)│   │
│  └─────────────────────────────────┘    │
│                  │                      │
│                  ▼                      │
│  ┌─────────────────────────────────┐    │
│  │    ModelAndView / @ResponseBody │    │
│  └─────────────────────────────────┘    │
│                  │                      │
│                  ▼                      │
│  ┌─────────────────────────────────┐    │
│  │    ViewResolver                 │    │
│  │    (视图解析器)                │    │
│  │  InternalResourceViewResolver   │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

4.2 代码示例

// Controller 类
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private UserMapper userMapper;
    
    // GET /api/users
    @GetMapping
    public ResponseEntity<PageResult<UserDTO>> list(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String keyword) {
        
        Page<User> userPage = userService.findAll(PageRequest.of(page - 1, size), keyword);
        List<UserDTO> dtoList = userMapper.toDTOList(userPage.getContent());
        
        return ResponseEntity.ok(PageResult.of(dtoList, userPage.getTotalElements()));
    }
    
    // GET /api/users/{id}
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getById(@PathVariable Long id) {
        User user = userService.findById(id);
        if (user == null) {
            throw new ResourceNotFoundException("User not found: " + id);
        }
        return ResponseEntity.ok(userMapper.toDTO(user));
    }
    
    // POST /api/users
    @PostMapping
    public ResponseEntity<UserDTO> create(
            @Valid @RequestBody UserCreateRequest request) {
        
        User user = userMapper.toEntity(request);
        User saved = userService.save(user);
        
        URI location = ServletUriComponentsBuilder
                .fromCurrentRequest()
                .path("/{id}")
                .buildAndExpand(saved.getId())
                .toUri();
        
        return ResponseEntity.created(location)
                .body(userMapper.toDTO(saved));
    }
    
    // PUT /api/users/{id}
    @PutMapping("/{id}")
    public ResponseEntity<UserDTO> update(
            @PathVariable Long id,
            @Valid @RequestBody UserUpdateRequest request) {
        
        User user = userService.findById(id);
        if (user == null) {
            throw new ResourceNotFoundException("User not found: " + id);
        }
        
        userMapper.updateEntity(user, request);
        User updated = userService.save(user);
        
        return ResponseEntity.ok(userMapper.toDTO(updated));
    }
    
    // DELETE /api/users/{id}
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }
    
    // 文件上传
    @PostMapping("/{id}/avatar")
    public ResponseEntity<String> uploadAvatar(
            @PathVariable Long id,
            @RequestParam("file") MultipartFile file) {
        
        String url = userService.uploadAvatar(id, file);
        return ResponseEntity.ok(url);
    }
}

4.3 全局异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    // 处理资源不存在
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException e) {
        ErrorResponse error = new ErrorResponse(
                HttpStatus.NOT_FOUND.value(),
                e.getMessage(),
                LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
    
    // 处理参数校验失败
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException e) {
        List<String> errors = e.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.toList());
        
        ErrorResponse error = new ErrorResponse(
                HttpStatus.BAD_REQUEST.value(),
                "Validation failed",
                errors,
                LocalDateTime.now()
        );
        return ResponseEntity.badRequest().body(error);
    }
    
    // 处理其他异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneric(Exception e) {
        log.error("Unexpected error", e);
        ErrorResponse error = new ErrorResponse(
                HttpStatus.INTERNAL_SERVER_ERROR.value(),
                "Internal server error",
                LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }
}

4.4 拦截器与配置

// 拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || !JwtUtil.validate(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("{\"error\":\"Unauthorized\"}");
            return false;
        }
        return true;
    }
}

// 配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private AuthInterceptor authInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/auth/**", "/api/public/**");
    }
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .maxAge(3600);
    }
    
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 配置 JSON 转换器
        MappingJackson2HttpMessageConverter converter = 
                new MappingJackson2HttpMessageConverter();
        converter.getObjectMapper()
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .registerModule(new JavaTimeModule());
        converters.add(0, converter);
    }
}

4.5 优缺点分析

优点缺点
注解驱动,开发效率高学习曲线较陡(需要理解 Spring 生态)
与 Spring 生态完美集成配置相对复杂(虽然 Spring Boot 已简化)
RESTful 支持优秀对于简单项目可能过于重量级
灵活的拦截器机制
强大的数据绑定和验证
广泛的社区支持和文档

五、阿里 ROP(RESTful 开放平台)

5.1 技术定位

ROP(Rapid Open Platform)是阿里巴巴开源的 RESTful 开放平台框架,专注于解决企业对外提供 API 服务的场景。

┌─────────────────────────────────────────────────────────────┐
│                      开放平台架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   第三方开发者        开放平台网关         内部服务           │
│       │                  │                  │               │
│       │  1.注册应用       │                  │               │
│       ├────────────────►│                  │               │
│       │  2.获取 AppKey   │                  │               │
│       │◄────────────────┤                  │               │
│       │                  │                  │               │
│       │  3.调用 API       │                  │               │
│       │  + AppKey        │                  │               │
│       │  + Sign 签名     │                  │               │
│       │  + Timestamp     │                  │               │
│       ├────────────────►│                  │               │
│       │                  │  4.校验签名       │               │
│       │                  │  5.限流检查       │               │
│       │                  │  6.权限校验       │               │
│       │                  ├────────────────►│               │
│       │                  │                  │               │
│       │                  │◄────────────────┤               │
│       │◄────────────────┤  7.返回结果       │               │
│       │                  │                  │               │
└─────────────────────────────────────────────────────────────┘

5.2 核心特性

// ROP 服务方法定义
@ServiceMethod(method = "user.get", 
               version = "1.0",
               httpMethod = {HttpMethod.GET})
public class UserGetService implements RopRequest<UserGetRequest> {
    
    @Autowired
    private UserService userService;
    
    @Override
    public UserGetResponse execute(UserGetRequest request, 
                                    ServiceContext context) {
        // ROP 自动完成:签名验证、限流、权限检查
        
        String userId = request.getUserId();
        User user = userService.getUser(userId);
        
        if (user == null) {
            // ROP 标准错误格式
            throw new ServiceError("USER_NOT_FOUND", "用户不存在");
        }
        
        UserGetResponse response = new UserGetResponse();
        response.setUserId(user.getId());
        response.setUserName(user.getName());
        response.setEmail(user.getEmail());
        
        return response;
    }
}

// 请求参数
public class UserGetRequest extends RopRequest {
    
    @NotNull
    @OpenField(desc = "用户ID", demoValue = "12345")
    private String userId;
    
    @OpenField(desc = "返回字段", demoValue = "id,name,email")
    private String fields;
    
    // Getters and Setters
}

// 响应结果
public class UserGetResponse implements RopResponse {
    
    @OpenField(desc = "用户ID")
    private String userId;
    
    @OpenField(desc = "用户名")
    private String userName;
    
    @OpenField(desc = "邮箱")
    private String email;
    
    // Getters and Setters
}

5.3 ROP 安全机制

// 签名算法示例
public class RopSignUtil {
    
    /**
     * 生成签名
     * 规则:MD5(AppSecret + 所有参数按key排序后的字符串 + AppSecret)
     */
    public static String sign(Map<String, String> params, String appSecret) {
        // 1. 过滤空值和签名本身
        Map<String, String> filtered = params.entrySet().stream()
                .filter(e -> e.getValue() != null && !e.getValue().isEmpty())
                .filter(e -> !"sign".equals(e.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        
        // 2. 按 key 排序
        List<String> sortedKeys = new ArrayList<>(filtered.keySet());
        Collections.sort(sortedKeys);
        
        // 3. 拼接字符串
        StringBuilder sb = new StringBuilder();
        sb.append(appSecret);
        for (String key : sortedKeys) {
            sb.append(key).append(filtered.get(key));
        }
        sb.append(appSecret);
        
        // 4. MD5 加密
        return DigestUtils.md5Hex(sb.toString()).toUpperCase();
    }
}

// 典型请求参数
// appKey=your_app_key
// method=user.get
// version=1.0
// timestamp=2024-01-15+10%3A30%3A00
// format=json
// userId=12345
// sign=E3F5A8B2C1D4E6F7...32位大写MD5

5.4 ROP 配置

<!-- rop-servlet.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rop="http://www.rop.com/schema/rop"
       xsi:schemaLocation="...">

    <!-- ROP 核心配置 -->
    <rop:annotation-driven/>
    
    <!-- 服务注册表 -->
    <rop:service-registry id="serviceRegistry"
                          service-expose-or-not="AUTO"/>
    
    <!-- 安全拦截器 -->
    <rop:security-interceptor app-checker="appChecker"
                               sign-checker="signChecker"
                               timestamp-checker="timestampChecker"/>
    
    <!-- 限流配置 -->
    <rop:limiting-interceptor limit-manager="limitManager"/>
    
    <!-- 监控配置 -->
    <rop:monitor-interceptor service-access-counter="accessCounter"/>
    
    <!-- 错误处理器 -->
    <bean id="errorHandler" class="com.example.rop.CustomErrorHandler"/>
    
</beans>

5.5 优缺点分析

优点缺点
完整的开放平台解决方案已停止维护(2015年后无更新)
内置安全机制(签名、限流、权限)生态封闭,社区支持少
标准化 API 格式仅适合特定场景(开放平台)
自动生成 API 文档与现代微服务架构兼容性差
完善的监控统计依赖较老的 Spring 版本

六、全面对比

6.1 功能特性对比

特性ServletStruts2Spring MVC阿里 ROP
学习成本⭐⭐ 低⭐⭐⭐⭐ 高⭐⭐⭐ 中⭐⭐⭐⭐ 高
开发效率⭐ 低⭐⭐⭐ 中⭐⭐⭐⭐⭐ 高⭐⭐⭐ 中
REST 支持⭐⭐ 需手动⭐⭐⭐ 插件⭐⭐⭐⭐⭐ 原生⭐⭐⭐⭐⭐ 原生
依赖注入❌ 无⭐⭐⭐ Spring⭐⭐⭐⭐⭐ Spring⭐⭐⭐ Spring
数据验证❌ 手动⭐⭐⭐⭐ XWork⭐⭐⭐⭐⭐ JSR-303⭐⭐⭐ 内置
安全性⭐⭐ 需自建⭐⭐⭐⭐ 拦截器⭐⭐⭐⭐ 拦截器⭐⭐⭐⭐⭐ 内置
生态系统⭐⭐⭐⭐ 成熟⭐⭐⭐ 衰退⭐⭐⭐⭐⭐ 活跃⭐ 已停止
微服务适配⭐⭐ 困难⭐⭐ 困难⭐⭐⭐⭐⭐ 优秀⭐⭐ 困难
性能⭐⭐⭐⭐⭐ 最高⭐⭐⭐ 一般⭐⭐⭐⭐ 良好⭐⭐⭐ 一般

6.2 代码量对比(实现相同功能)

假设实现用户 CRUD 接口:

框架代码行数(约)配置文件注解使用
Servlet300+web.xml
Struts2200+struts.xml少量
Spring MVC100+Java Config大量
阿里 ROP150+rop.xml中等

6.3 适用场景

                    项目规模
         小型 ◄────────────────────────► 大型
         
    传统  │  ┌──────────────────────────────┐
    企业  │  │         Struts2              │
    应用  │  │    (遗留系统维护)           │
         │  └──────────────────────────────┘
         │         ┌──────────────────────────────┐
应用类型  现代      │         Spring MVC           │
         API      │     (主流推荐方案)          │
         服务      │                              │
         │         └──────────────────────────────┘
         │  ┌──────────────────────────────┐
    开放  │  │         阿里 ROP             │
    平台  │  │    (特定场景/历史项目)      │
         │  └──────────────────────────────┘
    底层  │  ┌──────────────────────────────┐
    框架  │  │        Servlet/JSP           │
    开发  │  │    (框架开发/特殊需求)      │
         │  └──────────────────────────────┘

七、技术选型建议

7.1 新项目选型(2026年)

场景推荐方案理由
企业级 Web 应用Spring Boot + Spring MVC生态最完善,社区最活跃
微服务架构Spring WebFlux / Spring MVC响应式支持,云原生友好
RESTful API 服务Spring MVC + OpenAPI标准化 REST 开发
前后端分离Spring MVCJSON 支持优秀,CORS 配置简单

7.2 遗留系统维护

现有技术建议策略
Struts2逐步迁移到 Spring MVC,关注安全漏洞
Servlet/JSP如无重大问题可保留,新项目使用框架
阿里 ROP建议迁移到 Spring Cloud Gateway + 自定义安全

7.3 现代 Spring Boot 示例

// Spring Boot 3.x + Spring MVC
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    
    private final UserService userService;
    private final UserMapper userMapper;
    
    @GetMapping("/{id}")
    public UserDTO getUser(@PathVariable Long id) {
        return userService.findById(id)
                .map(userMapper::toDTO)
                .orElseThrow(() -> new NotFoundException("User not found"));
    }
    
    @PostMapping
    public ResponseEntity<UserDTO> create(@Valid @RequestBody CreateUserRequest request) {
        User user = userService.create(request);
        return ResponseEntity
                .created(URI.create("/api/v1/users/" + user.getId()))
                .body(userMapper.toDTO(user));
    }
}

// application.yml 配置
// server:
//   port: 8080
// spring:
//   mvc:
//     format:
//       date-time: yyyy-MM-dd HH:mm:ss

八、总结

技术诞生背景当前地位学习建议
ServletJava Web 基石仍需理解原理⭐⭐⭐⭐⭐ 必学
Struts2早期 MVC 框架维护中,不推荐新项目⭐⭐ 了解即可
Spring MVC现代企业级标准绝对主流⭐⭐⭐⭐⭐ 必学
阿里 ROP开放平台特定场景已停止维护⭐ 历史参考

趋势展望:

  • Servlet 规范继续演进(Jakarta EE)
  • Spring MVC 与 WebFlux 并存(响应式编程)
  • 云原生时代的框架演进(GraalVM 原生镜像支持)

参考资源: