ssm整合 ,ajax json请求406

'# SSM整合,AJAX JSON请求406错误的深度解析与实战指南

一、背景与问题

在SSM(Spring + Spring MVC + MyBatis)整合开发中,AJAX请求返回JSON数据时,常出现406 Not Acceptable错误。这种错误通常与HTTP协议的MIME类型协商机制有关。Spring MVC框架在处理请求时,会根据客户端请求头中的Accept字段判断是否支持指定的MIME类型(如application/json)。若服务器端未正确配置或未处理相应请求,就会返回406错误。

在实际开发中,常见的场景包括:前端通过AJAX请求后端接口获取数据时,后端未正确返回JSON格式,或未设置Content-Type头为application/json,导致客户端无法正确解析响应数据。

二、基本原理

Spring MVC处理AJAX请求的核心流程如下:

  1. 请求拦截:通过HandlerMapping匹配请求路径和控制器方法
  2. 参数绑定:通过HandlerAdapter解析请求参数
  3. 返回值处理:根据返回值类型决定响应格式(如ModelAndViewString@ResponseBody等)
  4. MIME类型协商:根据Accept头选择合适的响应格式
  5. 响应发送:通过HttpServletResponse返回响应数据

当使用@ResponseBody注解时,Spring会通过HttpMessageConverter将返回值转换为JSON格式。若未配置相关转换器(如Jackson库),或未正确设置Content-Type头,就会导致406错误。

三、环境准备

开发环境要求:

  • JDK 1.8+
  • Maven 3.x
  • Spring 5.x
  • Jackson 2.x
  • MySQL 8.x(可选)

项目结构建议:

src
├── main
│   ├── java
│   │   └── com.example.ssm
│   │       ├── controller
│   │       ├── service
│   │       └── dao
│   └── resources
│       ├── application.properties
│       └── springmvc-servlet.xml
└── test

四、核心实现

1. 基础配置(错误示例)

// 错误配置:未配置Jackson支持
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    // 未配置消息转换器
}

错误原因:Spring默认不包含Jackson库,导致无法处理JSON格式的返回值。

2. 正确配置(推荐方案)

// 正确配置:启用Jackson支持
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
        return new Jackson2ObjectMapperBuilder()
                .failOnUnknownProperties(false)
                .enable(FAIL_ON_EMPTY_BEAN)
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }
}

关键点:通过Jackson2ObjectMapperBuilder配置Jackson的格式化规则,确保JSON转换时的兼容性。

3. 控制器方法实现

@RestController
@RequestMapping("/api")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public ResponseEntity<List<User>> getUsers() {
        List<User> users = userService.findAll();
        return ResponseEntity.ok(users);
    }
}

关键点

  • 使用@RestController注解替代@Controller+@ResponseBody
  • ResponseEntity提供更灵活的响应控制
  • @GetMapping明确指定HTTP方法

五、完整案例

1. 项目结构

src
├── main
│   ├── java
│   │   └── com.example.ssm
│   │       └── controller
│   │           └── UserController.java
│   │       └── model
│   │           └── User.java
│   │       └── service
│   │           └── UserService.java
│   │       └── dao
│   │           └── UserDao.java
│   └── resources
│       └── application.properties

2. 配置文件

<!-- springmvc-servlet.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.example.ssm"/>
    <mvc:annotation-driven />
    <mvc:default-servlet-handler />
</beans>

3. 数据模型

// User.java
public class User {
    private Long id;
    private String name;
    private String email;
    
    // getters and setters
}

4. 前端调用示例

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>AJAX JSON Test</title>
</head>
<body>
    <button onclick="fetchUsers()">获取用户数据</button>
    <div id="result"></div>

    <script>
        function fetchUsers() {
            fetch('/api/users', {
                method: 'GET',
                headers: {
                    'Accept': 'application/json'
                }
            })
            .then(response => {
                if (!response.ok) throw new Error('Network response was not ok');
                return response.json();
            })
            .then(data => {
                const resultDiv = document.getElementById('result');
                resultDiv.textContent = JSON.stringify(data, null, 2);
            })
            .catch(error => {
                console.error('Error:', error);
            });
        }
    </script>
</body>
</html>

5. 控制器实现

// UserController.java
@RestController
@RequestMapping("/api")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public ResponseEntity<List<User>> getUsers() {
        List<User> users = userService.findAll();
        return ResponseEntity.ok(users);
    }
}

六、源码解析

Spring MVC处理JSON请求的核心流程如下:

  1. 请求拦截:通过HandlerMapping匹配路径,调用HandlerAdapter
  2. 参数绑定HandlerAdapter解析请求参数,调用HandlerMethodArgumentResolver
  3. 返回值处理:根据@ResponseBody注解,使用HttpMessageConverter转换返回值
  4. MIME类型协商:通过ContentNegotiationManager选择合适的转换器
  5. 响应发送:设置Content-Type头为application/json,写入响应体

关键代码片段(Jackson配置):

@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
    return new Jackson2ObjectMapperBuilder()
            .failOnUnknownProperties(false)
            .enable(FAIL_ON_EMPTY_BEAN)
            .dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}

七、进阶使用

1. 复杂数据转换

@GetMapping("/users")
public ResponseEntity<List<User>> getUsers() {
    List<User> users = userService.findAll();
    return ResponseEntity.ok(users);
}

2. POST请求处理

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
    User createdUser = userService.save(user);
    return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}

3. 异常处理

@ExceptionHandler
public ResponseEntity<String> handleException(Exception ex) {
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}

八、性能与工程实践

1. 性能优化

  • 缓存机制:对频繁访问的接口添加缓存
  • 异步处理:对耗时操作使用@Async注解
  • GZIP压缩:配置Content-Encoding头为gzip
  • 连接池配置:调整HttpClient的连接池参数

2. 安全风险

  • CSRF防护:对于POST请求需添加@EnableWebSecurity配置
  • 数据验证:使用@Valid注解进行参数校验
  • SQL注入:MyBatis中使用#{}参数绑定避免注入

九、常见问题与踩坑

1. 常见错误

问题原因解决方案
406错误未配置Jackson库添加Jackson依赖
400错误参数绑定失败检查@RequestBody字段类型
500错误异常未处理添加@ExceptionHandler
415错误未设置Content-Type在前端设置headers

2. 高级问题

  • 跨域问题:配置@CrossOrigin注解或使用CORS过滤器
  • 版本控制:通过@RequestMappingparams属性区分版本
  • 日志监控:在application.properties中配置logging.level级别

十、最佳实践

  1. 统一返回结构:定义Result类封装返回数据
  2. 接口版本控制:通过/api/v1/路径区分接口版本
  3. 分页处理:对大数据量接口使用分页机制
  4. 缓存策略:对静态数据接口添加缓存
  5. 异常处理:统一异常处理机制,避免暴露敏感信息

十一、总结

SSM整合中AJAX JSON请求406错误的根源在于HTTP MIME类型协商机制和Spring MVC的返回值处理机制。通过正确配置Jackson库、合理使用@RestController注解、配置Content-Type头等措施,可以有效解决该问题。在实际开发中,建议优先使用@RestController替代传统@Controller+@ResponseBody组合,同时注意处理跨域、异常、安全等潜在问题。对于高性能要求的场景,可考虑引入缓存、异步处理等优化手段。通过深入理解Spring MVC的处理流程,开发者可以更灵活地应对各种复杂的业务需求。

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日