首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Spring MVC JSON 傳值後端接收為 Key 問題排查

     編輯:程式設計疑難解答

問題現象

  • 前端 AJAX 發送 JSON:`{"username":"admin","password":"123"}`
  • Controller 參數為實體類 `User`
  • 資料庫插入後發現欄位值為「username」「password」等**鍵名字串**,而非實際值

根本原因排查清單

1. 缺少 `@RequestBody` 註解(最常見)


// 錯誤:Spring MVC 當作表單參數綁定,JSON 解析失敗
@PostMapping("/login")
public Result login(User user) { ... }

// 正確:明確告知從請求體讀取 JSON
@PostMapping("/login")
public Result login(@RequestBody User user) { ... }

2. 缺少 Jackson 依賴


<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

3. 實體類缺少無參建構子或 Getter/Setter


public class User {
    private String username;
    private String password;
    
    public User() {} // 必須
    
    // 必須有 Getter/Setter 或 public 欄位
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    // ...
}

4. 前端 Content-Type 錯誤


// jQuery AJAX
$.ajax({
    url: '/login',
    type: 'POST',
    contentType: 'application/json;charset=UTF-8', // 關鍵
    data: JSON.stringify({username: 'admin', password: '123'}),
    success: function(res) { ... }
});

// 或原生 fetch
fetch('/login', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({username: 'admin', password: '123'})
});

5. `@RequestBody` 與 `@RequestParam`/`@ModelAttribute` 衝突


// 錯誤:不能同時有 @RequestBody 和其他參數綁定註解
@PostMapping("/login")
public Result login(@RequestBody User user, @RequestParam String captcha) { ... }

// 正確:captcha 放入 User 物件,或用 @RequestHeader/@CookieValue
public class LoginForm {
    private String username;
    private String password;
    private String captcha;
    // getter/setter
}
@PostMapping("/login")
public Result login(@RequestBody LoginForm form) { ... }

完整正確範例

前端


<script>
function doLogin() {
    var data = {
        username: $('#username').val(),
        password: $('#password').val()
    };
    $.ajax({
        url: '${pageContext.request.contextPath}/api/login',
        type: 'POST',
        contentType: 'application/json;charset=UTF-8',
        data: JSON.stringify(data),
        dataType: 'json',
        success: function(resp) {
            if (resp.code === 200) location.href = '/index';
            else alert(resp.msg);
        }
    });
}
</script>

後端 Controller


@RestController
@RequestMapping("/api")
public class AuthController {
    
    @Autowired UserService userService;
    
    @PostMapping("/login")
    public Result login(@RequestBody @Valid LoginDTO dto, BindingResult binding) {
        if (binding.hasErrors()) {
            return Result.error(binding.getFieldError().getDefaultMessage());
        }
        return userService.login(dto);
    }
}

DTO 類別


@Data // Lombok 自動生成 getter/setter/toString
public class LoginDTO {
    @NotBlank(message = "用戶名不能為空")
    private String username;
    
    @NotBlank(message = "密碼不能為空")
    @Size(min = 6, max = 20, message = "密碼長度 6-20 位")
    private String password;
}

Service 層


@Service
public class UserService {
    @Autowired UserMapper userMapper;
    
    public Result login(LoginDTO dto) {
        User user = userMapper.findByUsername(dto.getUsername());
        if (user == null) return Result.error("用戶不存在");
        if (!passwordEncoder.matches(dto.getPassword(), user.getPassword())) 
            return Result.error("密碼錯誤");
        return Result.success(user);
    }
}

進階:全域 JSON 日期格式化


@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
            .dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
            .timeZone(TimeZone.getTimeZone("GMT+8"))
            .serializationInclusion(JsonInclude.Include.NON_NULL);
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }
}

除錯技巧

  1. 瀏覽器 Network 面板檢查 Request Payload 是否為合法 JSON
  2. Controller 加入 `@ControllerAdvice` 全域異常處理,捕獲 `HttpMessageNotReadableException` 印出原始請求體
  3. 單元測試用 `MockMvc` 模擬 JSON 請求驗證綁定
  4. 臨時在 Controller 印出 `user.toString()` 確認值是否為鍵名

常見錯誤對照表

現象原因修正
所有欄位為 null缺少 @RequestBody加上 @RequestBody
欄位值為 "username" 字串JSON 解析失敗,表單綁定將鍵名當值檢查 Content-Type、Jackson 依賴、DTO 結構
415 Unsupported Media TypeContent-Type 不匹配前端加 contentType: 'application/json'
日期反序列化失敗格式不匹配配置 ObjectMapper 日期格式

遵循「前端 JSON.stringify + Content-Type: application/json → 後端 @RequestBody + Jackson + DTO」標準鏈路,並善用 `@Valid` 驗證、全域異常處理,即可構建健壯的 JSON API 介面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved