Equivalent a Angular però per Backend
November 2025
Spring Boot és un framework per a la creació d'aplicacions Java autònomes, de producció i basades en Spring que s'executen amb la mínima configuració.
| Aspecte | Angular | Spring Boot |
|---|---|---|
| Tipus | Frontend Framework | Backend Framework |
| Estructura | Modular per features | Capes o features |
| Dependències | npm packages | Maven/Gradle |
| Configuració | angular.json | application.yml |
| Server | ng serve | Tomcat integrat |
| Build | ng build | mvn package |
# Opció 1: Spring Boot CLI
spring boot new --from web --name my-app --type maven
# Opció 2: Spring Initializr
# https://start.spring.io
# Opció 3: IDE
# New Project → Spring Boot
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
my-app/
├── src/main/java/com/example/myapp/
│ ├── MyAppApplication.java
│ ├── config/
│ ├── controller/
│ ├── service/
│ ├── repository/
│ ├── entity/
│ ├── dto/
│ ├── exception/
│ └── util/
├── src/main/resources/
├── src/test/java/
└── pom.xml
my-app/
├── src/main/java/com/example/myapp/
│ ├── MyAppApplication.java
│ ├── common/
│ │ ├── config/
│ │ └── exception/
│ ├── user/
│ │ ├── UserController.java
│ │ ├── UserService.java
│ │ └── User.java
│ ├── order/
│ │ ├── OrderController.java
│ │ └── Order.java
│ └── product/
│ └── ProductController.java
spring:
application:
name: my-app
datasource:
url: jdbc:mysql://localhost:3306/myapp
username: root
password: password
jpa:
hibernate:
ddl-auto: update
show-sql: false
servlet:
context-path: /api
server:
port: 8080
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/myapp_dev
jpa:
show-sql: true
# application-prod.yml
spring:
datasource:
url: jdbc:mysql://prod-db:3306/myapp_prod
jpa:
show-sql: false
@SpringBootApplication
public class MyAppApplication {
public static void main(String[] args) {
SpringApplication.run(MyAppApplication.class, args);
}
}
@Entity
@Table(name = "users")
@Data
@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 firstName;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
private Long id;
@NotBlank(message = "Email és obligatori")
@Email(message = "Email ha de ser vàlid")
private String email;
@NotBlank(message = "Nom és obligatori")
private String firstName;
@NotBlank(message = "Cognom és obligatori")
private String lastName;
}
@Repository
public interface UserRepository
extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
List<User> findByFirstNameContaining(String name);
}
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class UserService {
private final UserRepository userRepository;
public UserDTO createUser(UserDTO userDTO) {
log.info("Creating user: {}", userDTO.getEmail());
User user = new User();
user.setEmail(userDTO.getEmail());
user.setFirstName(userDTO.getFirstName());
User saved = userRepository.save(user);
return mapToDTO(saved);
}
}
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Tag(name = "Users")
public class UserController {
private final UserService userService;
@PostMapping
@Operation(summary = "Crear usuari")
public ResponseEntity<UserDTO> createUser(
@Valid @RequestBody UserDTO userDTO) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(userService.createUser(userDTO));
}
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(
@PathVariable Long id) {
return ResponseEntity.ok(
userService.getUserById(id));
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true);
}
}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<ErrorResponse>
handleNotFound(RuntimeException ex) {
ErrorResponse error = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage()
);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(error);
}
}
┌─────────────────────────────────┐
│ REST Controller (API) │
├─────────────────────────────────┤
│ Service Layer │
│ (Lògica de negoci) │
├─────────────────────────────────┤
│ Repository Layer │
│ (Accés a dades) │
├─────────────────────────────────┤
│ Entity/Model Layer │
│ (Mappeig de BD) │
└─────────────────────────────────┘
| Capa | Responsabilitat |
|---|---|
| Controller | Gestionar HTTP requests |
| Service | Lògica de negoci |
| Repository | Accés a dades |
| Entity | Mappeig a BD |
Els endpoints están disponibles a:
http://localhost:8080/api/swagger-ui.html
http://localhost:8080/api/v3/api-docs
Dependency requerida:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
@RestController
@RequestMapping("/api/v1/users")
@Tag(name = "Users", description = "API de Gestió")
public class UserController {
@PostMapping
@Operation(
summary = "Crear usuari",
description = "Crea un nou usuari al sistema"
)
@ApiResponse(
responseCode = "201",
description = "Usuari creat")
@ApiResponse(
responseCode = "400",
description = "Validació fallada")
public ResponseEntity<UserDTO> createUser(
@RequestBody UserDTO userDTO) {
// ...
}
}
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testCreateUser() {
User testUser = new User(
1L, "test@example.com",
"John", "Doe");
when(userRepository.save(any(User.class)))
.thenReturn(testUser);
UserDTO result = userService
.createUser(new UserDTO());
assertNotNull(result);
verify(userRepository, times(1))
.save(any(User.class));
}
}
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void testCreateUserEndpoint() throws Exception {
String userJson = """
{
"email": "test@example.com",
"firstName": "John",
"lastName": "Doe"
}
""";
mockMvc.perform(post("/api/v1/users")
.contentType("application/json")
.content(userJson))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.email")
.value("test@example.com"));
}
}
mvn clean package -DskipTests
# Resultat: target/my-app-1.0.0.jar
# Executar el JAR
java -jar target/my-app-1.0.0.jar
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/my-app-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/myapp
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: password
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: myapp
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
# Iniciar serveis
docker-compose up -d
# Veure logs
docker-compose logs -f app
# Aturar serveis
docker-compose down
@Slf4j
public class UserService {
public void processUser(Long userId) {
log.info("Processing user: {}", userId);
try {
// ...
} catch (Exception e) {
log.error("Error: {}", userId, e);
}
}
}
@Service
@RequiredArgsConstructor
public class OrderService {
@Transactional
public OrderDTO createOrder(OrderDTO dto) {
// Lògica de negoci
}
@Transactional(readOnly = true)
public OrderDTO getOrder(Long id) {
// Lectura
}
}
@Service
public class UserService {
@Transactional(readOnly = true)
public Page<UserDTO> getAllUsers(
Pageable pageable) {
return userRepository.findAll(pageable)
.map(this::mapToDTO);
}
}
PascalCase - Classes (UserController)camelCase - Mètodes (getUserById)SCREAMING_SNAKE_CASE - Constantssnake_case - BD fields (first_name)@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(
EntityNotFoundException ex) {
return new ErrorResponse(404,
ex.getMessage());
}
}
Per preguntes o suggeriments, contacta l'equip de desenvolupament.
Última actualització: November 2025