commit
1b409a3a6e
|
@ -3,16 +3,21 @@
|
||||||
This application exists as an example for the Lightrun series of articles.
|
This application exists as an example for the Lightrun series of articles.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
This application requires [Apache Maven](https://maven.apache.org/) and [Java 17+](https://www.oracle.com/java/technologies/downloads/).
|
This application requires [Apache Maven](https://maven.apache.org/) and [Java 17+](https://www.oracle.com/java/technologies/downloads/).
|
||||||
|
|
||||||
Building the code is done by executing:
|
Building the code is done by executing:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ mvn install
|
$ mvn install
|
||||||
```
|
```
|
||||||
|
|
||||||
from the top level.
|
from the top level.
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
The application consists of three services:
|
The application consists of three services:
|
||||||
|
|
||||||
* Tasks
|
* Tasks
|
||||||
* Users
|
* Users
|
||||||
* API
|
* API
|
||||||
|
@ -23,7 +28,9 @@ The Tasks and Users services exist as microservices for managing one facet of da
|
||||||
|
|
||||||
This does mean that the startup order is important. The JMS queue exists within the Tasks service and is connected to from the Users service. As such, the Tasks service must be started before the others.
|
This does mean that the startup order is important. The JMS queue exists within the Tasks service and is connected to from the Users service. As such, the Tasks service must be started before the others.
|
||||||
|
|
||||||
Each service can be started either by executing `mvn spring-boot:run` from within the appropriate directory. Alternatively, as Spring Boot applications, the build will produce an executable JAR file within the `target` directory that can be executed as, for example:
|
Each service can be started either by executing `mvn spring-boot:run` from within the appropriate directory. Alternatively, as Spring Boot applications, the build will produce an executable JAR file within the `target` directory that can be executed as, for
|
||||||
|
example:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ java -jar ./target/tasks-service-0.0.1-SNAPSHOT.jar
|
$ java -jar ./target/tasks-service-0.0.1-SNAPSHOT.jar
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
package com.baeldung.apiservice;
|
package com.baeldung.apiservice;
|
||||||
|
|
||||||
import org.slf4j.MDC;
|
import java.util.UUID;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.UUID;
|
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class RequestIdGenerator implements HandlerInterceptor {
|
public class RequestIdGenerator implements HandlerInterceptor {
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
String requestId = UUID.randomUUID().toString();
|
String requestId = UUID.randomUUID()
|
||||||
|
.toString();
|
||||||
|
|
||||||
MDC.put(RequestIdGenerator.class.getCanonicalName(), requestId);
|
MDC.put(RequestIdGenerator.class.getCanonicalName(), requestId);
|
||||||
response.addHeader("X-Request-Id", requestId);
|
response.addHeader("X-Request-Id", requestId);
|
||||||
|
|
|
@ -9,9 +9,9 @@ import org.springframework.web.client.RestTemplate;
|
||||||
public class RestTemplateConfig {
|
public class RestTemplateConfig {
|
||||||
@Bean
|
@Bean
|
||||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||||
return builder
|
return builder.additionalInterceptors((request, body, execution) -> {
|
||||||
.additionalInterceptors((request, body, execution) -> {
|
request.getHeaders()
|
||||||
request.getHeaders().add("X-Request-Id", RequestIdGenerator.getRequestId());
|
.add("X-Request-Id", RequestIdGenerator.getRequestId());
|
||||||
|
|
||||||
return execution.execute(request, body);
|
return execution.execute(request, body);
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,10 +2,5 @@ package com.baeldung.apiservice.adapters.http;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public record TaskResponse(String id,
|
public record TaskResponse(String id, String title, Instant created, UserResponse createdBy, UserResponse assignedTo, String status) {
|
||||||
String title,
|
|
||||||
Instant created,
|
|
||||||
UserResponse createdBy,
|
|
||||||
UserResponse assignedTo,
|
|
||||||
String status) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
package com.baeldung.apiservice.adapters.http;
|
package com.baeldung.apiservice.adapters.http;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.baeldung.apiservice.adapters.tasks.Task;
|
import com.baeldung.apiservice.adapters.tasks.Task;
|
||||||
import com.baeldung.apiservice.adapters.tasks.TaskRepository;
|
import com.baeldung.apiservice.adapters.tasks.TaskRepository;
|
||||||
import com.baeldung.apiservice.adapters.users.UserRepository;
|
import com.baeldung.apiservice.adapters.users.UserRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -27,12 +33,7 @@ public class TasksController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskResponse buildResponse(Task task) {
|
private TaskResponse buildResponse(Task task) {
|
||||||
return new TaskResponse(task.id(),
|
return new TaskResponse(task.id(), task.title(), task.created(), getUser(task.createdBy()), getUser(task.assignedTo()), task.status());
|
||||||
task.title(),
|
|
||||||
task.created(),
|
|
||||||
getUser(task.createdBy()),
|
|
||||||
getUser(task.assignedTo()),
|
|
||||||
task.status());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserResponse getUser(String userId) {
|
private UserResponse getUser(String userId) {
|
||||||
|
@ -47,6 +48,7 @@ public class TasksController {
|
||||||
|
|
||||||
return new UserResponse(user.id(), user.name());
|
return new UserResponse(user.id(), user.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(UnknownTaskException.class)
|
@ExceptionHandler(UnknownTaskException.class)
|
||||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||||
public void handleUnknownTask() {
|
public void handleUnknownTask() {
|
||||||
|
|
|
@ -2,10 +2,5 @@ package com.baeldung.apiservice.adapters.tasks;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public record Task(String id,
|
public record Task(String id, String title, Instant created, String createdBy, String assignedTo, String status) {
|
||||||
String title,
|
|
||||||
Instant created,
|
|
||||||
String createdBy,
|
|
||||||
String assignedTo,
|
|
||||||
String status) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.baeldung.apiservice.adapters.users;
|
package com.baeldung.apiservice.adapters.users;
|
||||||
|
|
||||||
import com.baeldung.apiservice.adapters.users.User;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.baelduung</groupId>
|
<groupId>com.baelduung</groupId>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
|
|
|
@ -13,10 +13,5 @@ package com.baeldung.tasksservice.adapters.http;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public record TaskResponse(String id,
|
public record TaskResponse(String id, String title, Instant created, String createdBy, String assignedTo, String status) {
|
||||||
String title,
|
|
||||||
Instant created,
|
|
||||||
String createdBy,
|
|
||||||
String assignedTo,
|
|
||||||
String status) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,6 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.baeldung.tasksservice.adapters.repository.TaskRecord;
|
|
||||||
import com.baeldung.tasksservice.service.TasksService;
|
|
||||||
import com.baeldung.tasksservice.service.UnknownTaskException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
@ -32,6 +29,10 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.baeldung.tasksservice.adapters.repository.TaskRecord;
|
||||||
|
import com.baeldung.tasksservice.service.TasksService;
|
||||||
|
import com.baeldung.tasksservice.service.UnknownTaskException;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
class TasksController {
|
class TasksController {
|
||||||
|
@ -46,8 +47,7 @@ class TasksController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public List<TaskResponse> searchTasks(@RequestParam("status") Optional<String> status,
|
public List<TaskResponse> searchTasks(@RequestParam("status") Optional<String> status, @RequestParam("createdBy") Optional<String> createdBy) {
|
||||||
@RequestParam("createdBy") Optional<String> createdBy) {
|
|
||||||
var tasks = tasksService.search(status, createdBy);
|
var tasks = tasksService.search(status, createdBy);
|
||||||
|
|
||||||
return tasks.stream()
|
return tasks.stream()
|
||||||
|
@ -67,16 +67,14 @@ class TasksController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PatchMapping("/{id}")
|
@PatchMapping("/{id}")
|
||||||
public TaskResponse patchTask(@PathVariable("id") String id,
|
public TaskResponse patchTask(@PathVariable("id") String id, @RequestBody PatchTaskRequest body) {
|
||||||
@RequestBody PatchTaskRequest body) {
|
|
||||||
var task = tasksService.updateTask(id, body.status(), body.assignedTo());
|
var task = tasksService.updateTask(id, body.status(), body.assignedTo());
|
||||||
|
|
||||||
return buildResponse(task);
|
return buildResponse(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskResponse buildResponse(final TaskRecord task) {
|
private TaskResponse buildResponse(final TaskRecord task) {
|
||||||
return new TaskResponse(task.getId(), task.getTitle(), task.getCreated(), task.getCreatedBy(),
|
return new TaskResponse(task.getId(), task.getTitle(), task.getCreated(), task.getCreatedBy(), task.getAssignedTo(), task.getStatus());
|
||||||
task.getAssignedTo(), task.getStatus());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(UnknownTaskException.class)
|
@ExceptionHandler(UnknownTaskException.class)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package com.baeldung.tasksservice.adapters.jms;
|
package com.baeldung.tasksservice.adapters.jms;
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.jms.annotation.JmsListener;
|
import org.springframework.jms.annotation.JmsListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.baeldung.tasksservice.service.DeletedUserService;
|
import com.baeldung.tasksservice.service.DeletedUserService;
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
|
|
||||||
package com.baeldung.tasksservice.adapters.repository;
|
package com.baeldung.tasksservice.adapters.repository;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "tasks")
|
@Table(name = "tasks")
|
||||||
|
@ -32,8 +33,7 @@ public class TaskRecord {
|
||||||
private String assignedTo;
|
private String assignedTo;
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
public TaskRecord(final String id, final String title, final Instant created, final String createdBy,
|
public TaskRecord(final String id, final String title, final Instant created, final String createdBy, final String assignedTo, final String status) {
|
||||||
final String assignedTo, final String status) {
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.created = created;
|
this.created = created;
|
||||||
|
|
|
@ -2,12 +2,12 @@ package com.baeldung.tasksservice.service;
|
||||||
|
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
import com.baeldung.tasksservice.adapters.repository.TaskRecord;
|
|
||||||
import com.baeldung.tasksservice.adapters.repository.TasksRepository;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.baeldung.tasksservice.adapters.repository.TaskRecord;
|
||||||
|
import com.baeldung.tasksservice.adapters.repository.TasksRepository;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class DeletedUserService {
|
public class DeletedUserService {
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
|
@ -11,29 +11,33 @@
|
||||||
|
|
||||||
package com.baeldung.tasksservice.service;
|
package com.baeldung.tasksservice.service;
|
||||||
|
|
||||||
import javax.transaction.Transactional;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.baeldung.tasksservice.adapters.repository.TaskRecord;
|
import javax.transaction.Transactional;
|
||||||
import com.baeldung.tasksservice.adapters.repository.TasksRepository;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.baeldung.tasksservice.adapters.repository.TaskRecord;
|
||||||
|
import com.baeldung.tasksservice.adapters.repository.TasksRepository;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class TasksService {
|
public class TasksService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private TasksRepository tasksRepository;
|
private TasksRepository tasksRepository;
|
||||||
|
|
||||||
public TaskRecord getTaskById(String id) {
|
public TaskRecord getTaskById(String id) {
|
||||||
return tasksRepository.findById(id).orElseThrow(() -> new UnknownTaskException(id));
|
return tasksRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new UnknownTaskException(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteTaskById(String id) {
|
public void deleteTaskById(String id) {
|
||||||
var task = tasksRepository.findById(id).orElseThrow(() -> new UnknownTaskException(id));
|
var task = tasksRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new UnknownTaskException(id));
|
||||||
tasksRepository.delete(task);
|
tasksRepository.delete(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +55,8 @@ public class TasksService {
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public TaskRecord updateTask(String id, Optional<String> newStatus, Optional<String> newAssignedTo) {
|
public TaskRecord updateTask(String id, Optional<String> newStatus, Optional<String> newAssignedTo) {
|
||||||
var task = tasksRepository.findById(id).orElseThrow(() -> new UnknownTaskException(id));
|
var task = tasksRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new UnknownTaskException(id));
|
||||||
|
|
||||||
newStatus.ifPresent(task::setStatus);
|
newStatus.ifPresent(task::setStatus);
|
||||||
newAssignedTo.ifPresent(task::setAssignedTo);
|
newAssignedTo.ifPresent(task::setAssignedTo);
|
||||||
|
@ -60,12 +65,8 @@ public class TasksService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TaskRecord createTask(String title, String createdBy) {
|
public TaskRecord createTask(String title, String createdBy) {
|
||||||
var task = new TaskRecord(UUID.randomUUID().toString(),
|
var task = new TaskRecord(UUID.randomUUID()
|
||||||
title,
|
.toString(), title, Instant.now(), createdBy, null, "PENDING");
|
||||||
Instant.now(),
|
|
||||||
createdBy,
|
|
||||||
null,
|
|
||||||
"PENDING");
|
|
||||||
tasksRepository.save(task);
|
tasksRepository.save(task);
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
server.port=8082
|
server.port=8082
|
||||||
|
|
||||||
spring.artemis.mode=EMBEDDED
|
spring.artemis.mode=EMBEDDED
|
||||||
spring.artemis.host=localhost
|
spring.artemis.host=localhost
|
||||||
spring.artemis.port=61616
|
spring.artemis.port=61616
|
||||||
|
|
||||||
spring.artemis.embedded.enabled=true
|
spring.artemis.embedded.enabled=true
|
||||||
|
|
||||||
spring.jms.template.default-destination=my-queue-1
|
spring.jms.template.default-destination=my-queue-1
|
||||||
|
|
||||||
logging.level.org.apache.activemq.audit.base=WARN
|
logging.level.org.apache.activemq.audit.base=WARN
|
||||||
logging.level.org.apache.activemq.audit.message=WARN
|
logging.level.org.apache.activemq.audit.message=WARN
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,21 @@
|
||||||
This application exists as an example for the Lightrun series of articles.
|
This application exists as an example for the Lightrun series of articles.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
This application requires [Apache Maven](https://maven.apache.org/) and [Java 17+](https://www.oracle.com/java/technologies/downloads/). It does use the Maven Wrapper, so it can be built with only Java available on the path.
|
This application requires [Apache Maven](https://maven.apache.org/) and [Java 17+](https://www.oracle.com/java/technologies/downloads/). It does use the Maven Wrapper, so it can be built with only Java available on the path.
|
||||||
|
|
||||||
As such, building the code is done by executing:
|
As such, building the code is done by executing:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ./mvnw install
|
$ ./mvnw install
|
||||||
```
|
```
|
||||||
|
|
||||||
from the top level.
|
from the top level.
|
||||||
|
|
||||||
## Running
|
## Running
|
||||||
|
|
||||||
The application consists of three services:
|
The application consists of three services:
|
||||||
|
|
||||||
* Tasks
|
* Tasks
|
||||||
* Users
|
* Users
|
||||||
* API
|
* API
|
||||||
|
@ -23,7 +28,9 @@ The Tasks and Users services exist as microservices for managing one facet of da
|
||||||
|
|
||||||
This does mean that the startup order is important. The JMS queue exists within the Tasks service and is connected to from the Users service. As such, the Tasks service must be started before the others.
|
This does mean that the startup order is important. The JMS queue exists within the Tasks service and is connected to from the Users service. As such, the Tasks service must be started before the others.
|
||||||
|
|
||||||
Each service can be started either by executing `mvn spring-boot:run` from within the appropriate directory. Alternatively, as Spring Boot applications, the build will produce an executable JAR file within the `target` directory that can be executed as, for example:
|
Each service can be started either by executing `mvn spring-boot:run` from within the appropriate directory. Alternatively, as Spring Boot applications, the build will produce an executable JAR file within the `target` directory that can be executed as, for
|
||||||
|
example:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ java -jar ./target/tasks-service-0.0.1-SNAPSHOT.jar
|
$ java -jar ./target/tasks-service-0.0.1-SNAPSHOT.jar
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
|
|
|
@ -11,6 +11,5 @@
|
||||||
|
|
||||||
package com.baeldung.usersservice.adapters.http;
|
package com.baeldung.usersservice.adapters.http;
|
||||||
|
|
||||||
public record UserResponse(String id,
|
public record UserResponse(String id, String name) {
|
||||||
String name) {
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,6 @@
|
||||||
|
|
||||||
package com.baeldung.usersservice.adapters.http;
|
package com.baeldung.usersservice.adapters.http;
|
||||||
|
|
||||||
import com.baeldung.usersservice.adapters.repository.UserRecord;
|
|
||||||
import com.baeldung.usersservice.service.UsersService;
|
|
||||||
import com.baeldung.usersservice.service.UnknownUserException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
@ -27,6 +24,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.baeldung.usersservice.adapters.repository.UserRecord;
|
||||||
|
import com.baeldung.usersservice.service.UnknownUserException;
|
||||||
|
import com.baeldung.usersservice.service.UsersService;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
class UsersController {
|
class UsersController {
|
||||||
|
@ -52,12 +53,12 @@ class UsersController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PatchMapping("/{id}")
|
@PatchMapping("/{id}")
|
||||||
public UserResponse patchUser(@PathVariable("id") String id,
|
public UserResponse patchUser(@PathVariable("id") String id, @RequestBody PatchUserRequest body) {
|
||||||
@RequestBody PatchUserRequest body) {
|
|
||||||
var user = usersService.updateUser(id, body.name());
|
var user = usersService.updateUser(id, body.name());
|
||||||
|
|
||||||
return buildResponse(user);
|
return buildResponse(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserResponse buildResponse(final UserRecord user) {
|
private UserResponse buildResponse(final UserRecord user) {
|
||||||
return new UserResponse(user.getId(), user.getName());
|
return new UserResponse(user.getId(), user.getName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,18 +11,17 @@
|
||||||
|
|
||||||
package com.baeldung.usersservice.service;
|
package com.baeldung.usersservice.service;
|
||||||
|
|
||||||
import javax.transaction.Transactional;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.transaction.Transactional;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.baeldung.usersservice.adapters.jms.JmsSender;
|
import com.baeldung.usersservice.adapters.jms.JmsSender;
|
||||||
import com.baeldung.usersservice.adapters.repository.UserRecord;
|
import com.baeldung.usersservice.adapters.repository.UserRecord;
|
||||||
import com.baeldung.usersservice.adapters.repository.UsersRepository;
|
import com.baeldung.usersservice.adapters.repository.UsersRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.jms.core.JmsTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UsersService {
|
public class UsersService {
|
||||||
|
@ -33,12 +32,14 @@ public class UsersService {
|
||||||
private JmsSender jmsSender;
|
private JmsSender jmsSender;
|
||||||
|
|
||||||
public UserRecord getUserById(String id) {
|
public UserRecord getUserById(String id) {
|
||||||
return usersRepository.findById(id).orElseThrow(() -> new UnknownUserException(id));
|
return usersRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new UnknownUserException(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteUserById(String id) {
|
public void deleteUserById(String id) {
|
||||||
var user = usersRepository.findById(id).orElseThrow(() -> new UnknownUserException(id));
|
var user = usersRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new UnknownUserException(id));
|
||||||
usersRepository.delete(user);
|
usersRepository.delete(user);
|
||||||
|
|
||||||
jmsSender.sendDeleteUserMessage(id);
|
jmsSender.sendDeleteUserMessage(id);
|
||||||
|
@ -46,7 +47,8 @@ public class UsersService {
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public UserRecord updateUser(String id, Optional<String> newName) {
|
public UserRecord updateUser(String id, Optional<String> newName) {
|
||||||
var user = usersRepository.findById(id).orElseThrow(() -> new UnknownUserException(id));
|
var user = usersRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new UnknownUserException(id));
|
||||||
|
|
||||||
newName.ifPresent(user::setName);
|
newName.ifPresent(user::setName);
|
||||||
|
|
||||||
|
@ -54,7 +56,8 @@ public class UsersService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRecord createUser(String name) {
|
public UserRecord createUser(String name) {
|
||||||
var user = new UserRecord(UUID.randomUUID().toString(), name);
|
var user = new UserRecord(UUID.randomUUID()
|
||||||
|
.toString(), name);
|
||||||
usersRepository.save(user);
|
usersRepository.save(user);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
server.port=8081
|
server.port=8081
|
||||||
|
|
||||||
spring.artemis.host=localhost
|
spring.artemis.host=localhost
|
||||||
spring.artemis.port=61616
|
spring.artemis.port=61616
|
||||||
|
|
||||||
spring.jms.template.default-destination=my-queue-1
|
spring.jms.template.default-destination=my-queue-1
|
||||||
|
|
||||||
logging.level.org.apache.activemq.audit.base=WARN
|
logging.level.org.apache.activemq.audit.base=WARN
|
||||||
logging.level.org.apache.activemq.audit.message=WARN
|
logging.level.org.apache.activemq.audit.message=WARN
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue