Skip to content

Commit 338fd51

Browse files
authored
Create a new sample: todo-web-api-use-oracle-db (#34)
* Create a new sample: todo-web-api-use-oracle-db * Move 'sample requests' into 'getting started' * Add 'Migration Steps' in README.md
1 parent 861fb4f commit 338fd51

File tree

15 files changed

+764
-0
lines changed

15 files changed

+764
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Todo Web API with Oracle Database
2+
3+
This sample application demonstrates a Spring Boot REST API for managing Todo items using an Oracle database with JPA. The application showcases Oracle-specific SQL features and data types such as VARCHAR2.
4+
5+
## Features
6+
7+
- CRUD operations for Todo items
8+
- Spring Data JPA with Oracle database
9+
- Custom SQL queries using Oracle-specific features
10+
- Oracle-specific data types and functions
11+
- RESTful API endpoints
12+
13+
## Prerequisites
14+
15+
- Java 17 or higher
16+
- Maven 3.8 or higher
17+
- Docker (for running Oracle database container)
18+
- Postman or any API testing tool (optional)
19+
20+
## Technology Stack
21+
22+
- Spring Boot 3.2.4
23+
- Spring Data JPA
24+
- Oracle Database 21c XE
25+
- Project Lombok
26+
- Maven
27+
28+
## Getting Started
29+
30+
### 1. Setting up Oracle Database with Docker
31+
32+
Run the following command to start an Oracle Database XE container:
33+
34+
```bash
35+
docker run -d --name oracle-xe \
36+
-p 1521:1521 \
37+
-e ORACLE_PWD=oracle \
38+
container-registry.oracle.com/database/express:latest
39+
```
40+
41+
Note: The first time you run this, it may take a few minutes for the database to initialize (typically 5-10 minutes). You can check if the database is ready by running:
42+
43+
```bash
44+
docker logs oracle-xe | grep "DATABASE IS READY TO USE"
45+
```
46+
47+
When you see the "DATABASE IS READY TO USE" message, the database is initialized and ready.
48+
49+
### 2. Clone the repository
50+
51+
```bash
52+
git clone <repository-url>
53+
cd todo-web-api-use-oracle-db
54+
```
55+
56+
### 3. Build and run the application
57+
58+
Once the Oracle database is ready, you can build and run the application:
59+
60+
```bash
61+
mvn clean spring-boot:run
62+
```
63+
64+
The application will automatically:
65+
1. Connect to the Oracle database using the SYSTEM account
66+
2. Create the necessary tables using the schema.sql file (via Spring Boot's automatic schema initialization)
67+
3. Insert sample data using the data.sql file (via Spring Boot's automatic data initialization)
68+
4. Start the web server on port 8080
69+
70+
### 4. Access Sample Requests
71+
72+
### Get All Todos
73+
74+
```bash
75+
curl -X GET http://localhost:8080/api/todos
76+
```
77+
78+
### Create a Todo Item
79+
80+
```bash
81+
curl -X POST http://localhost:8080/api/todos \
82+
-H "Content-Type: application/json" \
83+
-d '{
84+
"title": "Learn Oracle Database",
85+
"description": "Study Oracle-specific features and SQL syntax",
86+
"priority": 7,
87+
"dueDate": "2023-12-31T23:59:59"
88+
}'
89+
```
90+
91+
## API Endpoints
92+
93+
| Method | URL | Description |
94+
|--------|----------------------------------- |------------------------------------------------|
95+
| GET | /api/todos | Get all todo items |
96+
| GET | /api/todos/{id} | Get a specific todo item by ID |
97+
| POST | /api/todos | Create a new todo item |
98+
| PUT | /api/todos/{id} | Update a todo item |
99+
| DELETE | /api/todos/{id} | Delete a todo item |
100+
| GET | /api/todos/completed?completed=true| Get completed or incomplete todos |
101+
| GET | /api/todos/high-priority?minPriority=5 | Get todos with priority >= minPriority |
102+
| GET | /api/todos/search?keyword=project | Search todos by keyword |
103+
| GET | /api/todos/top-priority | Get top priority tasks |
104+
| GET | /api/todos/overdue | Get overdue tasks |
105+
| PUT | /api/todos/update-priority | Update priority for tasks before cutoff date |
106+
| GET | /api/todos/oracle-search?term=demo | Search using Oracle-specific functions |
107+
| GET | /api/todos/oracle-demo | Demonstrate Oracle-specific query features |
108+
| POST | /api/todos/run-oracle-operations | Run Oracle-specific database operations |
109+
110+
## Oracle-Specific Features
111+
112+
This sample demonstrates several Oracle-specific features:
113+
114+
1. Oracle data types (VARCHAR2)
115+
2. Oracle date functions (SYSDATE, SYSTIMESTAMP)
116+
3. Oracle string functions (SUBSTR, INSTR)
117+
4. Oracle-specific SQL syntax (ROWNUM)
118+
5. PL/SQL blocks for complex operations
119+
120+
## Migrate form Oracle DB to PostgreSQL
121+
122+
## Migration Prerequisites
123+
124+
- [Visual Studio Code](https://code.visualstudio.com/download)
125+
- [VS Code extension: GitHub Copilot app modernization for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.migrate-java-to-azure)
126+
127+
## Migration Steps
128+
129+
1. Open current sample in Visual Studio Code.
130+
1. Click `GitHub Copilot app modernization for Java`.
131+
> ![click-extension](./images/click-extension.png)
132+
1. Find `Oracle to PostgreSQL`.
133+
1. Click `Run formula`.
134+
> ![click-run-formula](./images/click-run-formula.png)
135+
1. GitHub Copilot makes a plan for migrating this sample.
136+
> ![list-the-steps](./images/list-the-steps.png)
137+
1. Click `Confirm` or `Continue` in the GitHub Copilot chat window if necessary, until the whole migration process finishes.
138+
1. If everything goes well, it will finish migration work and give a summary file.
139+
1. Click `keep` to save the changes.
140+
> ![click-keep-to-save-changes](./images/click-keep-to-save-changes.png)
117 KB
Loading
249 KB
Loading
118 KB
Loading
177 KB
Loading

todo-web-api-use-oracle-db/pom.xml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>3.2.4</version>
9+
<relativePath/> <!-- lookup parent from repository -->
10+
</parent>
11+
<groupId>com.microsoft.migration</groupId>
12+
<artifactId>todo-web-api-use-oracle-db</artifactId>
13+
<version>0.0.1-SNAPSHOT</version>
14+
<name>todo-web-api-use-oracle-db</name>
15+
<description>Todo Web API using Oracle Database</description>
16+
17+
<properties>
18+
<java.version>17</java.version>
19+
</properties>
20+
21+
<dependencies>
22+
<!-- Spring Boot Web -->
23+
<dependency>
24+
<groupId>org.springframework.boot</groupId>
25+
<artifactId>spring-boot-starter-web</artifactId>
26+
</dependency>
27+
28+
<!-- Spring Data JPA -->
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-data-jpa</artifactId>
32+
</dependency>
33+
34+
<!-- Oracle Database Driver -->
35+
<dependency>
36+
<groupId>com.oracle.database.jdbc</groupId>
37+
<artifactId>ojdbc11</artifactId>
38+
<scope>runtime</scope>
39+
</dependency>
40+
41+
<!-- Validation -->
42+
<dependency>
43+
<groupId>org.springframework.boot</groupId>
44+
<artifactId>spring-boot-starter-validation</artifactId>
45+
</dependency>
46+
47+
<!-- Lombok for reducing boilerplate code -->
48+
<dependency>
49+
<groupId>org.projectlombok</groupId>
50+
<artifactId>lombok</artifactId>
51+
<optional>true</optional>
52+
</dependency>
53+
54+
<!-- Spring Boot DevTools -->
55+
<dependency>
56+
<groupId>org.springframework.boot</groupId>
57+
<artifactId>spring-boot-devtools</artifactId>
58+
<scope>runtime</scope>
59+
<optional>true</optional>
60+
</dependency>
61+
62+
<!-- Test -->
63+
<dependency>
64+
<groupId>org.springframework.boot</groupId>
65+
<artifactId>spring-boot-starter-test</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
</dependencies>
69+
70+
<build>
71+
<plugins>
72+
<plugin>
73+
<groupId>org.springframework.boot</groupId>
74+
<artifactId>spring-boot-maven-plugin</artifactId>
75+
<configuration>
76+
<excludes>
77+
<exclude>
78+
<groupId>org.projectlombok</groupId>
79+
<artifactId>lombok</artifactId>
80+
</exclude>
81+
</excludes>
82+
</configuration>
83+
</plugin>
84+
</plugins>
85+
</build>
86+
87+
</project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.microsoft.migration.todo;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class TodoApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(TodoApplication.class, args);
11+
}
12+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.microsoft.migration.todo.controller;
2+
3+
import com.microsoft.migration.todo.model.TodoItem;
4+
import com.microsoft.migration.todo.service.TodoService;
5+
import com.microsoft.migration.todo.util.OracleSqlDemonstrator;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.*;
10+
11+
import java.time.LocalDateTime;
12+
import java.util.List;
13+
import java.util.Map;
14+
import java.util.Optional;
15+
16+
@RestController
17+
@RequestMapping("/api/todos")
18+
public class TodoController {
19+
20+
@Autowired
21+
private TodoService todoService;
22+
23+
@Autowired
24+
private OracleSqlDemonstrator oracleSqlDemonstrator;
25+
26+
@GetMapping
27+
public ResponseEntity<List<TodoItem>> getAllTodos() {
28+
return ResponseEntity.ok(todoService.getAllTodos());
29+
}
30+
31+
@GetMapping("/{id}")
32+
public ResponseEntity<TodoItem> getTodoById(@PathVariable Long id) {
33+
Optional<TodoItem> todo = todoService.getTodoById(id);
34+
return todo.map(ResponseEntity::ok)
35+
.orElseGet(() -> ResponseEntity.notFound().build());
36+
}
37+
38+
@PostMapping
39+
public ResponseEntity<TodoItem> createTodo(@RequestBody TodoItem todo) {
40+
return new ResponseEntity<>(todoService.createTodo(todo), HttpStatus.CREATED);
41+
}
42+
43+
@PutMapping("/{id}")
44+
public ResponseEntity<TodoItem> updateTodo(@PathVariable Long id, @RequestBody TodoItem todoDetails) {
45+
try {
46+
TodoItem updatedTodo = todoService.updateTodo(id, todoDetails);
47+
return ResponseEntity.ok(updatedTodo);
48+
} catch (RuntimeException ex) {
49+
return ResponseEntity.notFound().build();
50+
}
51+
}
52+
53+
@DeleteMapping("/{id}")
54+
public ResponseEntity<Void> deleteTodo(@PathVariable Long id) {
55+
try {
56+
todoService.deleteTodo(id);
57+
return ResponseEntity.noContent().build();
58+
} catch (Exception ex) {
59+
return ResponseEntity.notFound().build();
60+
}
61+
}
62+
63+
@GetMapping("/completed")
64+
public ResponseEntity<List<TodoItem>> getTodosByCompleted(@RequestParam boolean completed) {
65+
return ResponseEntity.ok(todoService.getTodosByCompleted(completed));
66+
}
67+
68+
@GetMapping("/high-priority")
69+
public ResponseEntity<List<TodoItem>> getHighPriorityTodos(@RequestParam(defaultValue = "5") int minPriority) {
70+
return ResponseEntity.ok(todoService.getHighPriorityTodos(minPriority));
71+
}
72+
73+
@GetMapping("/search")
74+
public ResponseEntity<List<TodoItem>> searchTodos(@RequestParam String keyword) {
75+
return ResponseEntity.ok(todoService.searchTodos(keyword));
76+
}
77+
78+
@GetMapping("/top-priority")
79+
public ResponseEntity<List<TodoItem>> getTopPriorityTasks(
80+
@RequestParam(defaultValue = "3") int priority,
81+
@RequestParam(defaultValue = "5") int limit) {
82+
return ResponseEntity.ok(todoService.getTopPriorityTasks(priority, limit));
83+
}
84+
85+
@GetMapping("/overdue")
86+
public ResponseEntity<List<TodoItem>> getOverdueTasks() {
87+
return ResponseEntity.ok(todoService.getOverdueTasks());
88+
}
89+
90+
@PutMapping("/update-priority")
91+
public ResponseEntity<Void> updateTasksPriority(
92+
@RequestParam LocalDateTime cutoffDate,
93+
@RequestParam int newPriority) {
94+
todoService.updateTasksWithOracle(cutoffDate, newPriority);
95+
return ResponseEntity.ok().build();
96+
}
97+
98+
@GetMapping("/oracle-search")
99+
public ResponseEntity<List<TodoItem>> searchWithOracleVarchar2(@RequestParam String term) {
100+
return ResponseEntity.ok(todoService.searchWithOracleVarchar2(term));
101+
}
102+
103+
// Endpoint to demonstrate raw Oracle SQL usage
104+
@GetMapping("/oracle-demo")
105+
public ResponseEntity<List<Map<String, Object>>> demonstrateOracleSpecificQuery(
106+
@RequestParam(defaultValue = "") String keyword,
107+
@RequestParam(defaultValue = "0") int minPriority) {
108+
return ResponseEntity.ok(oracleSqlDemonstrator.executeRawOracleQuery(keyword, minPriority));
109+
}
110+
111+
// Endpoint to run the Oracle operations demo
112+
@PostMapping("/run-oracle-operations")
113+
public ResponseEntity<String> runOracleOperations() {
114+
try {
115+
oracleSqlDemonstrator.performOracleSpecificOperations();
116+
return ResponseEntity.ok("Oracle-specific operations executed successfully");
117+
} catch (Exception e) {
118+
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
119+
.body("Error executing Oracle operations: " + e.getMessage());
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)