Source code for Lightrun articles
This commit is contained in:
33
lightrun/users-service/.gitignore
vendored
Normal file
33
lightrun/users-service/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
29
lightrun/users-service/README.md
Normal file
29
lightrun/users-service/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Lightrun Example Application - Tasks Management
|
||||
|
||||
This application exists as an example for the Lightrun series of articles.
|
||||
|
||||
## 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.
|
||||
|
||||
As such, building the code is done by executing:
|
||||
```
|
||||
$ ./mvnw install
|
||||
```
|
||||
from the top level.
|
||||
|
||||
## Running
|
||||
The application consists of three services:
|
||||
* Tasks
|
||||
* Users
|
||||
* API
|
||||
|
||||
These are all Spring Boot applications.
|
||||
|
||||
The Tasks and Users services exist as microservices for managing one facet of data. Each uses a database, and utilise a JMS queue between them as well. For convenience this infrastructure is all embedded in the applications.
|
||||
|
||||
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:
|
||||
```
|
||||
$ java -jar ./target/tasks-service-0.0.1-SNAPSHOT.jar
|
||||
```
|
||||
63
lightrun/users-service/pom.xml
Normal file
63
lightrun/users-service/pom.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?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"
|
||||
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>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.7</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>users-service</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>users-service</name>
|
||||
<description>Users Service for LightRun Article</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-artemis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,29 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageType;
|
||||
|
||||
@Configuration
|
||||
public class JmsConfig {
|
||||
@Bean
|
||||
public MessageConverter jacksonJmsMessageConverter() {
|
||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||
converter.setTargetType(MessageType.TEXT);
|
||||
converter.setTypeIdPropertyName("_type");
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.usersservice;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class UsersServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(UsersServiceApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.adapters.http;
|
||||
|
||||
public record CreateUserRequest(String name) {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.adapters.http;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record PatchUserRequest(Optional<String> name) {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.adapters.http;
|
||||
|
||||
public record UserResponse(String id,
|
||||
String name) {
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
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.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/")
|
||||
class UsersController {
|
||||
@Autowired
|
||||
private UsersService usersService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public UserResponse getUser(@PathVariable("id") String id) {
|
||||
var user = usersService.getUserById(id);
|
||||
return buildResponse(user);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public void deleteUser(@PathVariable("id") String id) {
|
||||
usersService.deleteUserById(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public UserResponse createUser(@RequestBody CreateUserRequest body) {
|
||||
var user = usersService.createUser(body.name());
|
||||
return buildResponse(user);
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}")
|
||||
public UserResponse patchUser(@PathVariable("id") String id,
|
||||
@RequestBody PatchUserRequest body) {
|
||||
var user = usersService.updateUser(id, body.name());
|
||||
|
||||
return buildResponse(user);
|
||||
}
|
||||
private UserResponse buildResponse(final UserRecord user) {
|
||||
return new UserResponse(user.getId(), user.getName());
|
||||
}
|
||||
|
||||
@ExceptionHandler(UnknownUserException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public void handleUnknownUser() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"local-users": {
|
||||
"host": "localhost:8081"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
GET http://{{host}}/baeldung HTTP/1.1
|
||||
|
||||
###
|
||||
GET http://{{host}}/unknown HTTP/1.1
|
||||
|
||||
###
|
||||
DELETE http://{{host}}/baeldung HTTP/1.1
|
||||
|
||||
###
|
||||
DELETE http://{{host}}/unknown HTTP/1.1
|
||||
|
||||
###
|
||||
POST http://{{host}} HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Testing"
|
||||
}
|
||||
###
|
||||
PATCH http://{{host}}/coxg HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Test Name"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.adapters.jms;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class JmsSender {
|
||||
@Autowired
|
||||
private JmsTemplate jmsTemplate;
|
||||
|
||||
public void sendDeleteUserMessage(String userId) {
|
||||
jmsTemplate.convertAndSend("deleted_user", userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.adapters.repository;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
public class UserRecord {
|
||||
@Id
|
||||
@Column(name = "user_id")
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
public UserRecord(final String id, final String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private UserRecord() {
|
||||
// Needed for JPA
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.adapters.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface UsersRepository extends JpaRepository<UserRecord, String> {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.service;
|
||||
|
||||
public class UnknownUserException extends RuntimeException {
|
||||
private final String id;
|
||||
|
||||
public UnknownUserException(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/****************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2022 OCLC, Inc. All Rights Reserved.
|
||||
*
|
||||
* OCLC proprietary information: the enclosed materials contain
|
||||
* proprietary information of OCLC, Inc. and shall not be disclosed in whole or in
|
||||
* any part to any third party or used by any person for any purpose, without written
|
||||
* consent of OCLC, Inc. Duplication of any portion of these materials shall include this notice.
|
||||
*
|
||||
******************************************************************************************************************/
|
||||
|
||||
package com.baeldung.usersservice.service;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.baeldung.usersservice.adapters.jms.JmsSender;
|
||||
import com.baeldung.usersservice.adapters.repository.UserRecord;
|
||||
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
|
||||
public class UsersService {
|
||||
@Autowired
|
||||
private UsersRepository usersRepository;
|
||||
|
||||
@Autowired
|
||||
private JmsSender jmsSender;
|
||||
|
||||
public UserRecord getUserById(String id) {
|
||||
return usersRepository.findById(id).orElseThrow(() -> new UnknownUserException(id));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteUserById(String id) {
|
||||
var user = usersRepository.findById(id).orElseThrow(() -> new UnknownUserException(id));
|
||||
usersRepository.delete(user);
|
||||
|
||||
jmsSender.sendDeleteUserMessage(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public UserRecord updateUser(String id, Optional<String> newName) {
|
||||
var user = usersRepository.findById(id).orElseThrow(() -> new UnknownUserException(id));
|
||||
|
||||
newName.ifPresent(user::setName);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public UserRecord createUser(String name) {
|
||||
var user = new UserRecord(UUID.randomUUID().toString(), name);
|
||||
usersRepository.save(user);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
server.port=8081
|
||||
|
||||
spring.artemis.host=localhost
|
||||
spring.artemis.port=61616
|
||||
|
||||
spring.jms.template.default-destination=my-queue-1
|
||||
|
||||
logging.level.org.apache.activemq.audit.base=WARN
|
||||
logging.level.org.apache.activemq.audit.message=WARN
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
CREATE TABLE users (
|
||||
user_id VARCHAR(36) PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO users(user_id, name) VALUES
|
||||
('baeldung', 'Baeldung'),
|
||||
('coxg', 'Graham');
|
||||
Reference in New Issue
Block a user