1. 项目概述
在JavaWeb开发中,数据访问层(DAO)与表示层(Servlet)之间的参数传递看似简单,实则暗藏玄机。我见过太多项目因为参数传递不当导致性能瓶颈、安全漏洞甚至系统崩溃。本文将分享我在电商、金融等多个领域项目中总结出的参数传递最佳实践。
2. 核心需求解析
2.1 典型场景分析
- 用户登录:Servlet接收表单参数 → DAO验证用户信息
- 商品查询:Servlet获取分页参数 → DAO执行SQL查询
- 订单创建:Servlet组装业务对象 → DAO持久化数据
2.2 关键痛点
- 类型安全问题:HTTP请求参数都是字符串,需要正确转换
- 性能问题:频繁的对象创建和转换开销
- 可维护性:参数传递方式混乱导致代码难以理解
3. 参数传递方案对比
3.1 基础方案:直接传递基本类型
java复制// Servlet层
String username = request.getParameter("username");
String password = request.getParameter("password");
// DAO层
public boolean validateUser(String username, String password) {
// 查询数据库...
}
注意:这种方式在参数超过3个时就会变得难以维护
3.2 进阶方案:使用Map集合
java复制Map<String, Object> params = new HashMap<>();
params.put("pageNo", Integer.parseInt(request.getParameter("pageNo")));
params.put("pageSize", 10);
// DAO接口
public List<Product> queryProducts(Map<String, Object> params);
优点:灵活扩展
缺点:类型不安全,IDE无法检查键名拼写错误
3.3 最佳实践:DTO对象传递
java复制// 定义查询DTO
public class ProductQueryDTO {
private Integer pageNo;
private Integer pageSize;
private String category;
// getters/setters...
}
// Servlet层组装
ProductQueryDTO query = new ProductQueryDTO();
query.setPageNo(Integer.parseInt(request.getParameter("pageNo")));
// DAO接口
public List<Product> queryProducts(ProductQueryDTO query);
4. 类型安全处理技巧
4.1 自动类型转换框架
推荐使用Apache Commons BeanUtils:
java复制ProductQueryDTO query = new ProductQueryDTO();
BeanUtils.populate(query, request.getParameterMap());
4.2 自定义类型转换器
处理特殊格式(如日期):
java复制public class DateConverter implements Converter {
public Object convert(Class type, Object value) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse((String)value);
}
}
// 注册转换器
ConvertUtils.register(new DateConverter(), Date.class);
5. 性能优化方案
5.1 对象池技术
对于高频调用的DTO:
java复制private static final Stack<ProductQueryDTO> pool = new Stack<>();
public static ProductQueryDTO borrowDTO() {
return pool.isEmpty() ? new ProductQueryDTO() : pool.pop();
}
public static void returnDTO(ProductQueryDTO dto) {
pool.push(dto);
}
5.2 线程局部变量
避免在多线程环境下重复创建对象:
java复制private static final ThreadLocal<ProductQueryDTO> threadLocal =
ThreadLocal.withInitial(ProductQueryDTO::new);
// 使用方式
ProductQueryDTO query = threadLocal.get();
query.setPageNo(1);
6. 安全防护措施
6.1 SQL注入防护
永远不要直接拼接SQL:
java复制// 错误示例
String sql = "SELECT * FROM users WHERE username='" + username + "'";
// 正确做法
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE username=?");
ps.setString(1, username);
6.2 XSS过滤
对输出内容进行转义:
java复制import org.apache.commons.text.StringEscapeUtils;
String safeOutput = StringEscapeUtils.escapeHtml4(rawInput);
7. 实战案例:电商订单系统
7.1 下单流程参数传递
java复制// OrderDTO设计
public class OrderDTO {
private Long userId;
private List<OrderItemDTO> items;
private AddressDTO address;
// 其他字段...
}
// Servlet层处理
OrderDTO order = new OrderDTO();
order.setUserId(getCurrentUserId());
order.setItems(parseItems(request));
order.setAddress(parseAddress(request));
// DAO层处理
orderDAO.createOrder(order);
7.2 分页查询优化
java复制// 分页查询DTO
public class PageQuery<T> {
private int pageNo;
private int pageSize;
private T queryParams;
// 附加分页计算结果...
}
// 使用示例
PageQuery<ProductQuery> pageQuery = new PageQuery<>();
pageQuery.setPageNo(1);
pageQuery.setQueryParams(productQuery);
// DAO接口
public PageResult<Product> queryProducts(PageQuery<ProductQuery> query);
8. 常见问题排查
8.1 空指针异常防护
java复制// 使用Optional避免NPE
Optional.ofNullable(request.getParameter("name"))
.ifPresent(name -> query.setName(name));
8.2 日期格式处理
java复制// 统一处理日期格式异常
try {
query.setCreateTime(parseDate(param));
} catch (ParseException e) {
throw new IllegalArgumentException("日期格式错误");
}
8.3 大数据量传输
对于大批量数据(如Excel导入):
java复制// 使用流式处理
try (InputStream is = request.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(is))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line);
}
}
9. 架构演进建议
9.1 领域驱动设计应用
java复制// 将业务逻辑封装在领域对象中
public class Order {
public void addItem(Product product, int quantity) {
// 验证库存、计算折扣等业务规则
}
}
// Servlet层调用
Order order = new Order(user);
order.addItem(product, quantity);
orderDAO.save(order);
9.2 前后端分离方案
使用JSON作为传输格式:
java复制// 使用Jackson处理JSON
ObjectMapper mapper = new ObjectMapper();
OrderDTO order = mapper.readValue(
request.getInputStream(), OrderDTO.class);
10. 工具类推荐
10.1 参数校验工具
Hibernate Validator示例:
java复制public class LoginDTO {
@NotBlank
@Size(min=6, max=20)
private String username;
@Pattern(regexp="^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$")
private String password;
}
// 校验使用
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Set<ConstraintViolation<LoginDTO>> violations =
factory.getValidator().validate(loginDTO);
10.2 对象映射工具
MapStruct示例:
java复制@Mapper
public interface ProductMapper {
ProductDTO toDTO(Product product);
Product toEntity(ProductDTO dto);
}
// 自动生成实现类
ProductMapper mapper = Mappers.getMapper(ProductMapper.class);