本文目录导读:

在Java中统一参数拼接流程,主要针对HTTP请求参数、SQL查询参数、日志拼接以及字符串模板等场景,不同场景有不同的最佳实践,但核心思想是避免手动拼接、防止注入、提高可读性。
以下是各场景下的统一流程方案:
HTTP 请求参数拼接(最常用)
场景:构建 GET 请求的 URL 查询参数(如GET /api?name=张三&age=25)。
推荐方案:使用 Spring 的 UriComponentsBuilder 或 HttpClient 的 URLEncodedUtils。
方案 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场景)。 - 对团队进行代码审查,确保参数拼接流程统一、安全。