@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private UserRepository userRepository;
private static final Set<String> ALLOWED_GROUP_COLUMNS =
Set.of("department", "status", "level");
private static final Set<String> ALLOWED_ORDER_COLUMNS =
Set.of("department", "status", "level", "count");
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable String id) {
try {
// Input validation
Long userId = Long.parseLong(id);
if (userId <= 0) {
return ResponseEntity.badRequest().build();
}
// SECURE: Parameterized query
String sql = "SELECT * FROM users WHERE id = ?";
User user = jdbcTemplate.queryForObject(sql, new UserRowMapper(), userId);
return ResponseEntity.ok(user);
} catch (NumberFormatException e) {
return ResponseEntity.badRequest().build();
} catch (EmptyResultDataAccessException e) {
return ResponseEntity.notFound().build();
}
}
@PostMapping("/users/search")
public List<User> searchUsers(@RequestBody UserSearchRequest request) {
// SECURE: Parameterized query with validation
List<Object> params = new ArrayList<>();
StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1");
if (request.getName() != null && !request.getName().trim().isEmpty()) {
String name = request.getName().trim();
if (name.length() > 100) {
throw new IllegalArgumentException("Name too long");
}
sql.append(" AND name LIKE ?");
params.add("%" + name + "%");
}
if (request.getDepartment() != null) {
// Validate department against allowed values
Set<String> validDepartments = Set.of("IT", "HR", "Finance", "Marketing");
if (!validDepartments.contains(request.getDepartment())) {
throw new IllegalArgumentException("Invalid department");
}
sql.append(" AND department = ?");
params.add(request.getDepartment());
}
if (request.getMinSalary() != null) {
if (request.getMinSalary() < 0) {
throw new IllegalArgumentException("Salary must be non-negative");
}
sql.append(" AND salary >= ?");
params.add(request.getMinSalary());
}
return jdbcTemplate.query(sql.toString(), new UserRowMapper(), params.toArray());
}
@GetMapping("/reports")
public List<Map<String, Object>> getReport(@RequestParam String groupBy,
@RequestParam String orderBy) {
// Input validation with whitelisting
if (!ALLOWED_GROUP_COLUMNS.contains(groupBy)) {
throw new IllegalArgumentException("Invalid groupBy column");
}
if (!ALLOWED_ORDER_COLUMNS.contains(orderBy)) {
throw new IllegalArgumentException("Invalid orderBy column");
}
// SECURE: Validated column names (safe since whitelisted)
String sql = String.format(
"SELECT %s, COUNT(*) as count FROM users GROUP BY %s ORDER BY %s",
groupBy, groupBy, orderBy
);
return jdbcTemplate.queryForList(sql);
}
// Alternative: Repository pattern with JPA
@GetMapping("/users/by-department")
public List<User> getUsersByDepartment(@RequestParam String department) {
// BEST: Use repository with built-in parameterization
return userRepository.findByDepartment(department);
}
}