Java参数拼接流程如何统一

wen java案例 28

本文目录导读:

Java参数拼接流程如何统一

  1. HTTP 请求参数拼接(最常用)
  2. SQL 参数拼接(防止 SQL 注入)
  3. 日志参数拼接(提高性能 & 可读性)
  4. 字符串模板拼接(通用场景)
  5. 统一流程的黄金法则

在Java中统一参数拼接流程,主要针对HTTP请求参数SQL查询参数日志拼接以及字符串模板等场景,不同场景有不同的最佳实践,但核心思想是避免手动拼接、防止注入、提高可读性

以下是各场景下的统一流程方案:


HTTP 请求参数拼接(最常用)

场景:构建 GET 请求的 URL 查询参数(如GET /api?name=张三&age=25)。

推荐方案:使用 SpringUriComponentsBuilderHttpClientURLEncodedUtils

方案 A:Spring UriComponentsBuilder(最推荐)

import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.Map;
public class HttpParamBuilder {
    public static URI buildGetUrl(String baseUrl, Map<String, String> params) {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl);
        params.forEach(builder::queryParam);
        return builder.build().encode().toUri();
    }
    // 示例
    public static void main(String[] args) {
        Map<String, String> params = Map.of(
            "name", "张三",
            "age", "25",
            "city", "北京"
        );
        URI uri = buildGetUrl("http://api.example.com/user", params);
        System.out.println(uri); 
        // 输出: http://api.example.com/user?name=%E5%BC%A0%E4%B8%89&age=25&city=%E5%8C%97%E4%BA%AC
    }
}

方案 B:Apache HttpClient 的 URLEncodedUtils

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class HttpParamBuilder {
    public static String buildQueryString(List<NameValuePair> params) {
        return URLEncodedUtils.format(params, StandardCharsets.UTF_8);
    }
    // 示例
    public static void main(String[] args) {
        List<NameValuePair> params = List.of(
            new BasicNameValuePair("name", "张三"),
            new BasicNameValuePair("age", "25")
        );
        String query = buildQueryString(params);
        System.out.println(query); 
        // 输出: name=%E5%BC%A0%E4%B8%89&age=25
    }
}

方案 C:手写通用工具(不依赖框架,但需处理编码)

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;
public class HttpParamBuilder {
    public static String buildQueryString(Map<String, String> params) {
        return params.entrySet().stream()
            .map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue()))
            .collect(Collectors.joining("&"));
    }
    private static String encode(String value) {
        return URLEncoder.encode(value, StandardCharsets.UTF_8);
    }
    // 示例
    public static void main(String[] args) {
        Map<String, String> params = Map.of("name", "张三", "age", "25");
        String query = buildQueryString(params);
        System.out.println(query); 
        // 输出: name=%E5%BC%A0%E4%B8%89&age=25
    }
}

SQL 参数拼接(防止 SQL 注入)

核心原则永远不要手动拼接 SQL 字符串,必须使用 PreparedStatement / 参数化查询

方案 A:JDBC PreparedStatement

String sql = "SELECT * FROM users WHERE name = ? AND age > ?";
try (PreparedStatement ps = connection.prepareStatement(sql)) {
    ps.setString(1, "张三");
    ps.setInt(2, 18);
    ResultSet rs = ps.executeQuery();
}

方案 B:MyBatis Plus QueryWrapper(最推荐)

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "张三")
       .gt("age", 18);
List<User> users = userMapper.selectList(wrapper);

方案 C:JPA CriteriaQuery(类型安全)

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root = query.from(User.class);
query.where(
    cb.equal(root.get("name"), "张三"),
    cb.gt(root.get("age"), 18)
);
List<User> users = entityManager.createQuery(query).getResultList();

日志参数拼接(提高性能 & 可读性)

核心原则:使用 SLF4J 的占位符 ,避免字符串拼接(特别是 操作)。

推荐方案(SLF4J + Logback)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
    private static final Logger log = LoggerFactory.getLogger(UserService.class);
    public void createUser(String name, int age) {
        // ✅ 正确:使用占位符,延迟求值
        log.info("创建用户: name={}, age={}", name, age);
        // ❌ 错误:字符串拼接 +,即使日志级别不输出也会执行
        // log.info("创建用户: name=" + name + ", age=" + age);
    }
}

进阶 - 避免参数对象 toString() 调用(使用 lambda)

log.debug("用户详情: {}", () -> user.toExpensiveString());

字符串模板拼接(通用场景)

方案 A:Java 15+ Text Blocks + String.format()

String name = "张三";
int age = 25;
String msg = String.format("姓名: %s, 年龄: %d", name, age);

方案 B:MessageFormat(国际化场景)

import java.text.MessageFormat;
String pattern = "用户 {0} 的年龄是 {1}";
String msg = MessageFormat.format(pattern, "张三", 25);

方案 C:Apache Commons Lang3 StringSubstitutor(模板替换)

import org.apache.commons.text.StringSubstitutor;
import java.util.Map;
Map<String, Object> params = Map.of("name", "张三", "age", 25);
String template = "用户 ${name} 的年龄是 ${age}";
String result = StringSubstitutor.replace(template, params);
// 输出: 用户 张三 的年龄是 25

统一流程的黄金法则

场景 推荐方式 核心原因
HTTP GET参数 UriComponentsBuilder / URLEncodedUtils 自动编码,防止非法字符
HTTP POST参数 MultiValueMap + HttpEntity 类型安全,支持多值
SQL查询 PreparedStatement / ORM框架 防SQL注入
日志 SLF4J占位符 延迟求值,避免无谓性能损耗
通用字符串拼接 String.format() / MessageFormat 可读性强,支持国际化
复杂模板 StringSubstitutor / Thymeleaf 支持变量替换、条件逻辑

最终建议

  • 在项目中定义统一的 ParamUtils 工具类(或使用现有类库如Spring、Apache Commons)。
  • 禁止在代码中出现 "a=" + a + "&b=" + b 这种手写拼接(尤其在HTTP和SQL场景)。
  • 对团队进行代码审查,确保参数拼接流程统一、安全。

抱歉,评论功能暂时关闭!