You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java Spring控制器中转义请求体中的引号?

当然可以用Spring实现请求参数的引号转义!

不过先敲个重点:直接转义引号来做SQL净化并不是最安全的方案,优先推荐你用预编译SQL语句(比如JDBC的PreparedStatement)或者ORM框架(JPA/Hibernate)来处理SQL查询,这才是防止SQL注入的标准做法。但如果你确实需要对请求中的引号做转义处理,下面几种Spring的实现方式可以帮到你:


方法1:在控制器中用@InitBinder处理参数

@InitBinder是Spring提供的用于初始化WebDataBinder的注解,你可以利用它在参数绑定到控制器方法前,对请求参数做自定义处理。针对你用@RequestBody接收Map的场景,可以这样写:

@RestController
public class YourController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Map.class, new PropertyEditorSupport() {
            @Override
            public void setValue(Object value) {
                if (value instanceof Map) {
                    Map<String, String> paramMap = (Map<String, String>) value;
                    // 遍历Map,对每个value的引号进行转义
                    paramMap.replaceAll((key, val) -> {
                        if (val == null) return null;
                        // 这里以SQL常用的单引号转义为例:把'换成''
                        return val.replace("'", "''");
                        // 如果是需要转义双引号,可以换成val.replace("\"", "\\\"");
                    });
                    super.setValue(paramMap);
                } else {
                    super.setValue(value);
                }
            }
        });
    }

    @RequestMapping(method = RequestMethod.POST)
    public List<String[]> myEndpoint(@RequestBody Map<String, String> params, @AuthenticationPrincipal Account connectedUser) throws Exception {
        // 这里的params已经完成了引号转义
        return myService.runQuery(params, connectedUser);
    }
}

这个方法只作用于当前控制器,如果只有这一个端点需要处理,用这个很方便。


方法2:全局自定义RequestBodyAdvice处理

如果你的多个控制器都需要做引号转义,全局处理会更高效。你可以实现RequestBodyAdvice接口,在请求体被解析后统一处理:

@ControllerAdvice
public class QuoteEscapeRequestBodyAdvice implements RequestBodyAdvice {

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 只处理目标类型为Map<String, String>的请求体
        return targetType instanceof ParameterizedType &&
                ((ParameterizedType) targetType).getRawType().equals(Map.class) &&
                ((ParameterizedType) targetType).getActualTypeArguments()[0].equals(String.class) &&
                ((ParameterizedType) targetType).getActualTypeArguments()[1].equals(String.class);
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return inputMessage;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        if (body instanceof Map) {
            Map<String, String> paramMap = (Map<String, String>) body;
            paramMap.replaceAll((key, val) -> {
                if (val == null) return null;
                // 同样按需求转义引号,这里示例转义单引号
                return val.replace("'", "''");
            });
            return paramMap;
        }
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }
}

加上@ControllerAdvice注解后,这个处理逻辑会对所有符合条件的@RequestBody请求生效,不用在每个控制器重复写代码。


重要提醒

  1. 转义规则要根据你的SQL方言调整:比如MySQL用\'转义单引号,而Oracle用''转义,一定要对应正确。
  2. 再次强调:转义引号不能完全防止SQL注入,比如如果参数里包含特殊字符组合,还是可能存在风险。强烈建议你改用预编译语句或者ORM框架来构建SQL,从根源上避免注入问题。

内容的提问来源于stack exchange,提问作者Matthias Beaupère

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:27:48