Spring Boot
Controllers & Services
// REST Controller
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<Page<UserDto>> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String search) {
var pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
return ResponseEntity.ok(userService.findAll(pageable, search));
}
@GetMapping("/{id}")
public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findById(id));
}
@PostMapping
public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
var user = userService.create(request);
return ResponseEntity.created(URI.create("/api/users/" + user.getId())).body(user);
}
@PatchMapping("/{id}")
public ResponseEntity<UserDto> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
return ResponseEntity.ok(userService.update(id, request));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
// Service
@Service
@Transactional
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final UserMapper userMapper;
@Transactional(readOnly = true)
public Page<UserDto> findAll(Pageable pageable, String search) {
var page = search != null
? userRepository.findByNameContainingIgnoreCase(search, pageable)
: userRepository.findAll(pageable);
return page.map(userMapper::toDto);
}
@Transactional(readOnly = true)
public UserDto findById(Long id) {
return userRepository.findById(id)
.map(userMapper::toDto)
.orElseThrow(() -> new ResourceNotFoundException("User", id.toString()));
}
public UserDto create(CreateUserRequest request) {
if (userRepository.existsByEmail(request.getEmail())) {
throw new ConflictException("Email already registered");
}
var user = userMapper.toEntity(request);
user.setPassword(passwordEncoder.encode(request.getPassword()));
return userMapper.toDto(userRepository.save(user));
}
}JPA Entity & Repository
@Entity
@Table(name = "users", indexes = {
@Index(columnList = "email", unique = true),
@Index(columnList = "created_at")
})
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@JsonIgnore
private String password;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role = Role.USER;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Post> posts = new ArrayList<>();
@CreationTimestamp
@Column(updatable = false)
private Instant createdAt;
@UpdateTimestamp
private Instant updatedAt;
}
// Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
Page<User> findByNameContainingIgnoreCase(String name, Pageable pageable);
@Query("SELECT u FROM User u WHERE u.role = :role AND u.createdAt > :since")
List<User> findActiveUsersByRole(@Param("role") Role role, @Param("since") Instant since);
}Global Exception Handler & Validation
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors()
.forEach(e -> errors.put(e.getField(), e.getDefaultMessage()));
return ResponseEntity.badRequest().body(new ValidationErrorResponse(errors));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneric(Exception ex) {
log.error("Unexpected error", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Internal server error"));
}
}
// DTO with validation
public record CreateUserRequest(
@Email @NotBlank String email,
@NotBlank @Size(min = 2, max = 100) String name,
@NotBlank @Size(min = 8) String password
) {}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free