Spring Boot Angular Full Stack සංවර්ධනය - Ultimate Guide

අයියෝ! ඉතින් කොහොමද යාලුවනේ? අද අපි කතා කරන්න යන්නේ මේ දවස්වල Software Engineering ලෝකේ හරිම ජනප්රිය සංකලනයක් ගැන. ඒ තමයි backend එකට Spring Boot, frontend එකට Angular පාවිච්චි කරලා කොහොමද නියම full-stack application එකක් හදාගන්නේ කියන එක. ඇත්තටම මේ දෙක එකතු උනාම ලැබෙන බලය කියලා නිම කරන්න බැහැ. ඔයාට modern web application එකක් හදන්න ඕන නම්, scalable, maintainable, security features තියෙන එකක් නම්, මේ සංකලනය ඔයාට හොඳටම ඇති.
මචං, අපි කවුරුත් දන්නවනේ හොඳ ගෙයක් හදන්න නම් ශක්තිමත් අත්තිවාරමක් ඕන කියලා. ඒ වගේ තමයි web application එකකටත් ශක්තිමත් backend එකක් තියෙන්නම ඕන. Spring Boot කියන්නේ Java ecosystem එකේ ඉන්නකොට, ඒකට කියාපු විසඳුම. ඒ වගේම, හොඳ ලස්සන interface එකක් නැත්නම් user කෙනෙක් අපේ application එකත් එක්ක වැඩ කරන්න කැමති වෙන්නේ නැහැ. ඒකට Angular, Google ලාගේම framework එකක් නිසා, හරිම බලගතුයි. Typescript වල power එකත් එක්ක component-based architecture එකක් තියෙන Angular, ඉක්මනින් ලස්සන, dynamic user interfaces හදාගන්න උදව් වෙනවා. ඉතින්, අපි බලමු මේ දෙන්නව එකට යාළු කරලා, කොහොමද වැඩේ ගොඩදාගන්නේ කියලා!
ඇයි Spring Boot සහ Angular එකටම?
හරි, දැන් ඔයාට හිතෙන්න පුළුවන් ඇයි මේ දෙකම පාවිච්චි කරන්නේ කියලා. වෙන frameworks ඕන තරම් තියෙනවනේ. ඒත් මචං, මේක ටිකක් විශේෂයි. අපි බලමු මේ දෙකේ තියෙන වාසි මොනවද කියලා:
1. Robust Backend (Spring Boot)
- Scalability: Spring Boot application එකක් ලේසියෙන් scale කරන්න පුළුවන්. ඒ කියන්නේ users ලා වැඩි උනත්, application එකේ performance එක maintain කරන්න පුළුවන්.
- Security: Spring Security වගේ modules එක්ක හරිම පහසුවෙන් authentication, authorization වගේ දේවල් implement කරන්න පුළුවන්. අපිට තියෙන්නේ ටිකක් configure කරන්න විතරයි.
- Spring Ecosystem: Spring කියන්නේ හරිම විශාල ecosystem එකක්. Spring Data JPA, Spring AOP, Spring Cloud වගේ දේවල් එක්ක එකතු වෙලා වැඩ කරන කොට, development process එක හරිම පහසු වෙනවා.
- Java's Power: Java කියන්නේ enterprise level applications වලට හොඳටම ගැලපෙන, කාලයක් තිස්සේ ඔප්පු වෙච්ච programming language එකක්. Performance, reliability අතින් නම් ඉහලින්ම තියෙනවා.
2. Dynamic Frontend (Angular)
- Component-Based Architecture: Angular වලදී අපි application එක හදන්නේ පුංචි පුංචි components වලින්. මේකෙන් code එක maintain කරන්න, reuse කරන්න හරිම පහසුයි.
- TypeScript: TypeScript කියන්නේ JavaScript වල superset එකක්. ඒ කියන්නේ JavaScript වලට වඩා extra features තියෙනවා, විශේෂයෙන්ම type safety එක. මේකෙන් development කාලේදී errors අඩුවෙනවා, code quality එක වැඩිවෙනවා.
- Rich UI: Angular Material, Ng-Bootstrap වගේ libraries එක්ක ලස්සන, responsive user interfaces හරිම පහසුවෙන් හදාගන්න පුළුවන්.
- Google Support: Google ලාම maintain කරන framework එකක් නිසා, හොඳ documentation, විශාල community එකක් සහ නිතරම updates තියෙනවා.
3. Separation of Concerns
මේක තමයි මේකේ ලොකුම වාසියක්. Backend එකයි Frontend එකයි වෙන වෙනම තියෙන නිසා, දෙගොල්ලන්ටම තමන්ගේ වැඩේට විතරක් අවධානය දෙන්න පුළුවන්. Backend team එකට API develop කරන්න, database එක්ක වැඩ කරන්න පුළුවන්, frontend team එකට user interface එක, user experience එක ගැන හිතලා develop කරන්න පුළුවන්. මේකෙන් development speed එක වැඩි වෙනවා වගේම, maintainability එකත් ඉහල යනවා.
Backend එක හදමු: Spring Boot API
හරි, දැන් අපි backend එක හදන්න පටන් ගමු. අපි හදමු Product management API එකක්. Product එකක් add කරන්න, තියෙන products ටික බලන්න පුළුවන් විදියට.
1. Project Setup
මුලින්ම ඔයා Spring Initializr (start.spring.io
) එකට ගිහින් project එකක් generate කරගන්න ඕන. Dependencies විදියට මේ ටික add කරගන්න:
- Spring Web: RESTful APIs හදන්න.
- Spring Data JPA: Database එක්ක වැඩ කරන්න.
- H2 Database: Development වලට embedded database එකක් විදියට. (production වලට PostgreSQL වගේ එකක් පාවිච්චි කරන්න පුළුවන්.)
- Lombok: Boilerplate code අඩු කරන්න.
Project එක download කරගෙන, ඔයාගේ IDE එකට (IntelliJ IDEA, VS Code වගේ) import කරගන්න.
2. Product Model
src/main/java/com/yourcompany/productapi/model/Product.java
වගේ file එකක් හදාගෙන මේ code එක add කරන්න:
package com.yourcompany.productapi.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
}
මෙහිදී, @Entity
කියන්නේ මේක database table එකකට map වෙනවා කියන එක. @Id
කියන්නේ primary key එක, @GeneratedValue
කියන්නේ database එකෙන් auto-generate වෙනවා කියන එක. Lombok ගේ @Data
, @NoArgsConstructor
, @AllArgsConstructor
වලින් getters, setters, constructors වගේ දේවල් auto generate වෙනවා, අපිට ලියන්න ඕන වෙන්නේ නැහැ. වැඩේ පහසුයි නේද?
3. Product Repository
src/main/java/com/yourcompany/productapi/repository/ProductRepository.java
වගේ file එකක් හදාගෙන මේ code එක add කරන්න:
package com.yourcompany.productapi.repository;
import com.yourcompany.productapi.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
}
JpaRepository
එක extend කිරීමෙන්, අපිට database operations (save, find, delete වගේ) ලියන්න ඕන වෙන්නේ නැහැ. Spring Data JPA එකෙන්ම ඒ ටික automatic generate කරලා දෙනවා. හරිම ලේසියි.
4. Product Controller
src/main/java/com/yourcompany/productapi/controller/ProductController.java
වගේ file එකක් හදාගෙන මේ code එක add කරන්න:
package com.yourcompany.productapi.controller;
import com.yourcompany.productapi.model.Product;
import com.yourcompany.productapi.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductRepository productRepository;
@GetMapping
public List<Product> getAllProducts() {
return productRepository.findAll();
}
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productRepository.save(product);
}
}
@RestController
කියන්නේ මේ class එක RESTful API එකක් කියලා Spring ට කියන එක. @RequestMapping("/api/products")
කියන්නේ මේ controller එකේ හැම method එකක්ම /api/products
කියන path එකෙන් පටන් ගන්නවා කියන එක. @Autowired
වලින් Spring ට කියනවා ProductRepository
එකේ instance එකක් මේකට inject කරන්න කියලා. @GetMapping
කියන්නේ GET request වලට මේ method එක respond කරනවා කියන එක, @PostMapping
කියන්නේ POST request වලට respond කරනවා කියන එක. @RequestBody
වලින් කියන්නේ request body එකේ එන JSON object එක Product object එකකට map කරන්න කියලා.
5. CORS Configuration (අත්යවශ්යයි!)
මේක තමයි backend එකයි frontend එකයි සම්බන්ධ කරනකොට අනිවාර්යයෙන්ම අවධානය දෙන්න ඕන වැදගත්ම දේ. ඔයාගේ Angular application එක වෙන port එකක (සාමාන්යයෙන් 4200) run වෙන නිසා, backend එකට (සාමාන්යයෙන් 8080) requests යවනකොට CORS (Cross-Origin Resource Sharing) කියන security mechanism එක නිසා requests block වෙන්න පුළුවන්. ඒකට අපි Spring Boot application එකට කියන්න ඕන, http://localhost:4200
එකෙන් එන requests වලට අවසර දෙන්න කියලා.
src/main/java/com/yourcompany/productapi/config/WebConfig.java
වගේ file එකක් හදාගෙන මේ code එක add කරන්න:
package com.yourcompany.productapi.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:4200") // Angular app URL
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
මෙහිදී .allowedOrigins("http://localhost:4200")
කියන line එක හරිම වැදගත්. මේකෙන් අපි කියනවා මේ URL එකෙන් එන requests වලට අවසර දෙන්න කියලා. .allowedMethods
වලින් අපි කියනවා මේ methods වලට අවසර දෙන්න කියලා. .allowedHeaders("*")
කියන්නේ ඕනෑම header එකකට අවසර දෙන්න කියලා, .allowCredentials(true)
කියන්නේ cookies, authentication headers වගේ ඒවා යවන්න අවසර දෙන්න කියලා.
දැන් ඔයාගේ Spring Boot application එක run කරන්න. (IDE එකෙන් හෝ mvn spring-boot:run
or ./gradlew bootRun
). http://localhost:8080/api/products
කියන URL එකට ගිහින් බලන්න පුළුවන්. මුලින් data නැතිව හිස් Array එකක් එන්න ඕන.
Frontend එක හදමු: Angular App
හරි, දැන් අපි Frontend එක හදමු. අපි හදපු Spring Boot API එකට requests යවලා data අරගෙන, display කරන්න පුළුවන් විදියට Angular application එකක් හදමු.
1. Project Setup
මුලින්ම Angular CLI එක install කරලා නැත්නම් install කරගන්න:
npm install -g @angular/cli
ඊට පස්සේ අලුත් Angular project එකක් generate කරගන්න:
ng new product-frontend --skip-tests --no-standalone
cd product-frontend
--skip-tests
සහ --no-standalone
කියන්නේ මේ tutorial එකට test files සහ standalone components ඕන නැති නිසා. ඔයාට ඕන නම් මේවා නැතුව generate කරගන්න පුළුවන්. දැන් අපි මේ project එකට HttpClientModule
එක add කරන්න ඕන. src/app/app.module.ts
එකට මේක add කරන්න:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http'; // මේක add කරන්න
import { FormsModule } from '@angular/forms'; // Input fields වලට
import { AppComponent } from './app.component';
import { ProductListComponent } from './product-list/product-list.component'; // මේකත් add කරන්න
@NgModule({
declarations: [
AppComponent,
ProductListComponent
],
imports: [
BrowserModule,
HttpClientModule, // මේක add කරන්න
FormsModule // මේකත් add කරන්න
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
දැන් අපි ProductListComponent එකක් හදාගමු:
ng generate component product-list
2. Product Model (Frontend)
Backend එකේ වගේම frontend එකටත් Product model එකක් ඕන. src/app/product.model.ts
වගේ file එකක් හදාගෙන මේ code එක add කරන්න:
export interface Product {
id?: number; // Optional, because it's generated by backend
name: string;
price: number;
}
මේක TypeScript interface එකක්. Backend එකේ Product object එක වගේම තමයි මේකත්. id
එක optional කරලා තියෙන්නේ backend එකෙන් generate වෙන නිසා.
3. Product Service
API calls handle කරන්න අපි service එකක් හදාගන්නවා. මේක හොඳ practice එකක්. src/app/product.service.ts
වගේ file එකක් හදාගෙන මේ code එක add කරන්න:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Product } from './product.model';
@Injectable({
providedIn: 'root'
})
export class ProductService {
private apiUrl = 'http://localhost:8080/api/products'; // Spring Boot API URL
constructor(private http: HttpClient) { }
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.apiUrl);
}
addProduct(product: Product): Observable<Product> {
return this.http.post<Product>(this.apiUrl, product);
}
}
@Injectable({ providedIn: 'root' })
කියන්නේ මේ service එක application එක පුරාම use කරන්න පුළුවන් කියන එක. HttpClient
එක අපි constructor එකට inject කරලා තියෙනවා. getProducts()
method එකෙන් GET
request එකක් යවනවා. addProduct()
method එකෙන් POST
request එකක් යවනවා. මේවා Observable
return කරන්නේ, Angular වල asynchronous operations handle කරන්න මේක තමයි standard way එක.
4. Product List Component (Display සහ Add කරන්න)
දැන් අපි අපේ ProductListComponent
එකට logic එකයි, HTML එකයි add කරමු.
src/app/product-list/product-list.component.ts
import { Component, OnInit } from '@angular/core';
import { ProductService } from '../product.service';
import { Product } from '../product.model';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
products: Product[] = [];
newProduct: Product = { name: '', price: 0 }; // New product form data
constructor(private productService: ProductService) { }
ngOnInit(): void {
this.loadProducts(); // Load products when component initializes
}
loadProducts(): void {
this.productService.getProducts().subscribe({
next: (data) => {
this.products = data;
console.log('Products loaded:', data);
},
error: (error) => {
console.error('Error loading products:', error);
alert('Failed to load products. Check console for details.');
}
});
}
addProduct(): void {
if (this.newProduct.name.trim() === '' || this.newProduct.price <= 0) {
alert('Please enter valid product name and price.');
return;
}
this.productService.addProduct(this.newProduct).subscribe({
next: (product) => {
this.products.push(product); // Add new product to list
this.newProduct = { name: '', price: 0 }; // Clear form
console.log('Product added:', product);
},
error: (error) => {
console.error('Error adding product:', error);
alert('Failed to add product. Check console for details.');
}
});
}
}
ngOnInit()
කියන්නේ component එක load වෙනකොට run වෙන method එක. ඒක ඇතුලේ අපි loadProducts()
call කරනවා. subscribe()
method එක හරිම වැදගත්. API එකට request එක යැව්වාට පස්සේ ලැබෙන response එක handle කරන්නේ මේකෙන්. next
වලින් සාර්ථක response එක handle කරනවා, error
වලින් error එකක් ආවොත් handle කරනවා. addProduct()
method එකෙන් form එකේ data අරගෙන backend එකට POST
request එකක් යවනවා.
src/app/product-list/product-list.component.html
<div class="container">
<h2>Products List</h2>
<div *ngIf="products.length === 0">
<p>No products found. Add some below!</p>
</div>
<ul>
<li *ngFor="let product of products">
<strong>{{ product.name }}</strong> - Rs. {{ product.price | number:'1.2-2' }}
</li>
</ul≯
<h3>Add New Product</h3>
<form (ngSubmit)="addProduct()">
<div class="form-group">
<label for="productName">Product Name:</label>
<input type="text" id="productName" [(ngModel)]="newProduct.name" name="name" placeholder="Enter product name" required>
</div>
<div class="form-group">
<label for="productPrice">Price:</label>
<input type="number" id="productPrice" [(ngModel)]="newProduct.price" name="price" placeholder="Enter price" required>
</div>
<button type="submit">Add Product</button>
</form>
</div>
*ngIf="products.length === 0"
වලින් කියන්නේ products නැත්නම් message එකක් පෙන්නන්න කියලා. *ngFor="let product of products"
වලින් products array එක iterate කරලා, එකින් එක display කරනවා. [(ngModel)]="newProduct.name"
කියන්නේ two-way data binding. ඒ කියන්නේ input field එකේ value එක newProduct.name
එකට auto update වෙනවා, ඒ වගේම newProduct.name
එක update උනොත් input field එකත් update වෙනවා. (ngSubmit)="addProduct()"
වලින් form එක submit කරනකොට addProduct()
method එක call කරනවා.
අවසාන වශයෙන්, src/app/app.component.html
එකේ තියෙන content ටික අයින් කරලා මේක add කරන්න:
<app-product-list></app-product-list>
සම්බන්ධ කරමු: API එක Angular එක්ක යාළු කරමු
දැන් Spring Boot backend එකත්, Angular frontend එකත් ලෑස්තියි. අපි බලමු කොහොමද මේ දෙන්නව එකට වැඩ කරවන්නේ කියලා.
1. Servers දෙකම Run කරන්න
මුලින්ම, ඔයාගේ Spring Boot application එක run වෙවී තියෙන්න ඕන. (http://localhost:8080
). ඊට පස්සේ Angular application එක run කරන්න:
ng serve
මේක run වෙනවා http://localhost:4200
එකේ. දැන් ඔයාගේ browser එකේ http://localhost:4200
කියන URL එකට යන්න. Product list එක හිස් වෙලා, add කරන්න form එකක් පෙන්නන්න ඕන. Product එකක් add කරලා බලන්න. Network tab එක (Browser Developer Tools) check කරලා බලන්න requests යනවද, responses එනවද කියලා.
2. CORS ගැන ආයෙත්
ඔයා මුලින් Spring Boot backend එකේ CORS config එක දැම්මේ නැත්නම්, මේ වෙලාවේදී ඔයාට error එකක් එන්න පුළුවන්. ඒක තමයි “Cross-Origin Request Blocked” වගේ error එකක්. ඒක තමයි මම කිව්වේ ඒක අත්යවශ්යයි කියලා. ඒ නිසා, Spring Boot එකේ CORS config එක හරියට දාලා, application එක restart කරලා බලන්න.
3. Development Proxy (විකල්ප විසඳුමක්)
සමහර වෙලාවට development වලදී CORS issues වලට තවත් විසඳුමක් විදියට Angular development server එකට proxy එකක් දාන්න පුළුවන්. මේකෙන් වෙන්නේ Angular app එකට එන /api
requests ටික, ඔයාගේ backend server එකට යොමු කරන එක. මේක production වලට හොඳ නැතත්, development වලදී පහසුයි. ඔයාගේ Angular project එකේ root එකේ proxy.conf.json
කියලා file එකක් හදාගෙන මේ code එක add කරන්න:
{
"/api": {
"target": "http://localhost:8080",
"secure": false,
"changeOrigin": true
}
}
ඊට පස්සේ, Angular app එක run කරද්දි මේ විදියට run කරන්න:
ng serve --proxy-config proxy.conf.json
මේකෙන් පස්සේ ඔයාට ProductService
එකේ apiUrl
එක මේ විදියට වෙනස් කරන්න පුළුවන්:
private apiUrl = '/api/products'; // No need for full URL now
මේකෙන් Angular app එක /api/products
කියන එකට request එක යවනකොට, proxy එක ඒක http://localhost:8080/api/products
කියන එකට හරවනවා. මේකෙන් CORS issue එකක් එන්නේ නැහැ, මොකද browser එකට පේන්නේ request එක එකම origin එකකින් යනවා වගේ.
ඉදිරි ගමන සහ අවසන් වචනය
දැන් ඔයාට හොඳටම වැටහෙනවා ඇති Spring Boot backend එකක් එක්ක Angular frontend එකක් කොහොමද සම්බන්ධ කරන්නේ කියලා. මේක තමයි full-stack development වල මූලිකම පියවර. මචං, මේකෙන් නතර වෙන්න එපා. තව ගොඩක් දේවල් තියෙනවා ඔයාට මේකට add කරන්න පුළුවන්. උදාහරණයක් විදියට:
- Authentication and Authorization: Spring Security (JWT tokens එක්ක) පාවිච්චි කරලා users ලා login කරවන්න, access control කරන්න පුළුවන්.
- State Management: Angular වලට NgRx හෝ Akita වගේ state management libraries පාවිච්චි කරලා complex application state එක manage කරන්න පුළුවන්.
- Error Handling: API calls වලදී errors handle කරන්න තව හොඳ strategies develop කරන්න පුළුවන්.
- Deployment: Docker, Heroku, AWS, DigitalOcean වගේ platform එකක මේ application එක deploy කරන්නේ කොහොමද කියලා ඉගෙන ගන්න.
- Testing: Unit tests, Integration tests ලියන්න ඉගෙන ගන්න.
ඉතින් යාලුවනේ, මේ guide එක ඔයාට ගොඩක් වැදගත් වෙන්න ඇති කියලා හිතනවා. Spring Boot සහ Angular කියන්නේ මේ දවස්වල industries වල ගොඩක් ඉල්ලුමක් තියෙන technologies දෙකක්. මේ දෙකේ දැනුම ඔයාගේ career එකට ලොකු boost එකක් වෙයි. මේක practice කරන්න, experiments කරන්න, අලුත් දේවල් හදන්න බලන්න. මොකද code කරලා ඉගෙන ගන්න එක තරම් හොඳ දෙයක් තවත් නැහැ.
මතක තියාගන්න, Software Engineering කියන්නේ නිතරම අලුත් දේවල් ඉගෙන ගන්න තියෙන ක්ෂේත්රයක්. ඒ නිසා නිතරම updated වෙලා ඉන්න. ඔයාට මේ post එක ගැන මොනවා හරි ප්රශ්න තියෙනවා නම්, comment section එකේ අහන්න. ඔයා මේක try කරලා බැලුවොත්, ඔයාගේ අත්දැකීම් share කරන්නත් අමතක කරන්න එපා. අපි ඊළඟ article එකෙන් හමුවෙමු! හැමෝටම ජය වේවා!